因为自定义拦截器,导致不支持jsonb相关的语法

我们的项目是多租户的,所以同事自定义了MyBatis的拦截器,在该拦截器中获取请求头中传递过来的租户Id,然后注入到所有的SQL中,其具体实现方式我暂时没有研究(我暂时没有计划去系统研究MyBatis-Plus)。

问题在于使用该方案后,会导致如下的代码无法正常执行:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

@Mapper
public interface ProjectMapper extends BaseMapper<Project> {

    // @InterceptorIgnore(tenantLine = "true")
    Project getProjectFileOrMaterialDepotCatalogueId(
            @Param("tenantId") String tenantId,
            @Param("catalogueId") String catalogueId);

}

1
2
3
4
5
6
7
8
9

<select id="getProjectFileOrMaterialDepotCatalogueId" resultType="com.sdstc.pdm.server.entity.Project">
    select *
    from t_project
    where org_id = #{tenantId} and
            ((catalogue_info::jsonb ->> 'projectFileCatalogueId') = #{catalogueId}
            or (catalogue_info::jsonb ->> 'materialDepotCatalogueId') = #{catalogueId})
</select>

具体报错如下:


Caused by: net.sf.jsqlparser.parser.ParseException: Encountered unexpected token: "->>" "->>"
    at line 4, column 39.

Was expecting one of:

    "&"
    "&&"
    ")"
    "::"
    "<<"
    ">>"
    "AND"
    "["
    "^"
    "|"

	at net.sf.jsqlparser.parser.CCJSqlParser.generateParseException(CCJSqlParser.java:25031)
	at net.sf.jsqlparser.parser.CCJSqlParser.jj_consume_token(CCJSqlParser.java:24875)
	at net.sf.jsqlparser.parser.CCJSqlParser.AndExpression(CCJSqlParser.java:8062)
	at net.sf.jsqlparser.parser.CCJSqlParser.OrExpression(CCJSqlParser.java:8008)
	at net.sf.jsqlparser.parser.CCJSqlParser.AndExpression(CCJSqlParser.java:8134)
	at net.sf.jsqlparser.parser.CCJSqlParser.OrExpression(CCJSqlParser.java:8008)
	at net.sf.jsqlparser.parser.CCJSqlParser.Expression(CCJSqlParser.java:7979)
	at net.sf.jsqlparser.parser.CCJSqlParser.WhereClause(CCJSqlParser.java:6922)
	at net.sf.jsqlparser.parser.CCJSqlParser.PlainSelect(CCJSqlParser.java:4075)
	at net.sf.jsqlparser.parser.CCJSqlParser.SetOperationList(CCJSqlParser.java:4264)
	at net.sf.jsqlparser.parser.CCJSqlParser.SelectBody(CCJSqlParser.java:3923)
	at net.sf.jsqlparser.parser.CCJSqlParser.Select(CCJSqlParser.java:3916)
	at net.sf.jsqlparser.parser.CCJSqlParser.SingleStatement(CCJSqlParser.java:130)
	at net.sf.jsqlparser.parser.CCJSqlParser.Statement(CCJSqlParser.java:81)
	at net.sf.jsqlparser.parser.CCJSqlParserUtil.parse(CCJSqlParserUtil.java:63)
	... 84 more

该问题其实之前没出现过的这个问题的,该如何处理呢,将ProjectMapper.java改为如下内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

@Mapper
public interface ProjectMapper extends BaseMapper<Project> {

    @InterceptorIgnore(tenantLine = "true")
    Project getProjectFileOrMaterialDepotCatalogueId(
            @Param("tenantId") String tenantId,
            @Param("catalogueId") String catalogueId);

}

解决这个问题花费了我整整一个上午的时间,实际上我根本不需要花费这么长时间解决这个问题,因为我一开始就尝试了正确的方案,结果因为其他的Bug,导致我认为自己的方案有问题。对解决这个问题的过程进行复盘,有如下问题:

  1. 项目做如此底层的调整,没有通知到所有的开发人员。
  2. 项目做了调整后,开发却忘记提交相关的配置文件,导致我这边无论如何尝试,都是错误的。

因为注入了自定义拦截器,导致pg的->>无法不可用,同事使用的解决方案是使用${operation}->>作为一个参数传入到SQL中,这样就可以避免JSQLParser对此的解析。我觉得这是一种不优雅的写法,所以我还是比较推荐上面的写法。

解决此问题的过程中,我尝试了如下的方案:

  1. 升级和降级JSQLParser
  2. 使用InterceptorIgnore注解
  3. 使用SQLParser注解
  4. 使用bind标签
  5. 使用参数传递->>操作

我觉得可能有更优雅的方案,比如在开发注解时下点功夫,但是暂时没有精力研究相关问题。