MyBatis-Plus 多租户插件条件位置问题记录

84 阅读2分钟

🐛 问题现象

在使用 MyBatis-Plus 多租户插件(TenantLineInnerInterceptor)时,发现以下代码片段在某些位置会报错:

<if test="bo.params.beginTime!=null and bo.params.beginTime!='' and bo.params.endTime!=null and bo.params.endTime!=''">
    AND (t1.up_shelf_time between #{bo.params.beginTime} and #{bo.params.endTime})
</if>

报错信息:

Caused by: net.sf.jsqlparser.parser.ParseException: Encountered unexpected token: "AND" "AND"

🔍 问题原因

经过排查,发现这是 MyBatis-Plus 多租户插件的一个解析bug,具体原因:

  1. 插件解析顺序敏感:TenantLineInnerInterceptor 在解析SQL时对条件位置敏感
  2. JSqlParser 限制:底层使用的 SQL 解析器对复杂条件拼接处理存在缺陷
  3. 条件组合冲突:当多个动态条件组合时,特定位置的 BETWEEN 条件会引发解析错误

✅ 解决方案

方案一:调整条件位置(当前有效)

将时间条件往前放置即可解决:

WHERE 1=1
<!-- 时间条件必须放在前面 -->
<if test="bo != null and bo.params != null 
          and bo.params.beginTime != null and bo.params.beginTime != '' 
          and bo.params.endTime != null and bo.params.endTime != ''">
    AND (t1.up_shelf_time between #{bo.params.beginTime} and #{bo.params.endTime})
</if>

<!-- 其他条件放在后面 -->
<if test="otherCondition != null">
    AND other_condition = #{value}
</if>

方案二:避免使用 BETWEEN

使用独立的比较条件更稳定:

WHERE 1=1
<if test="bo != null and bo.params != null 
          and bo.params.beginTime != null and bo.params.beginTime != '' 
          and bo.params.endTime != null and bo.params.endTime != ''">
    AND t1.up_shelf_time &gt;= #{bo.params.beginTime}
    AND t1.up_shelf_time &lt;= #{bo.params.endTime}
</if>

📝 注意事项

  1. 这不是代码逻辑问题,而是 MyBatis-Plus 插件的解析bug
  2. 条件顺序影响结果:某些条件需要放在特定位置才能正常工作
  3. XML 转义重要:始终使用 &gt;= 和 &lt;= 代替 >= 和 <=
  4. NULL 值处理:注意时间字段为 NULL 时的处理逻辑

🚨 影响范围

  • MyBatis-Plus 版本:3.4.3+(具体版本待确认)
  • 仅影响使用 TenantLineInnerInterceptor 多租户插件的场景
  • 主要涉及包含 BETWEEN 条件的动态SQL

📋 后续行动

  1. 在团队文档中记录此问题
  2. 考虑升级 MyBatis-Plus 版本测试是否修复
  3. 如持续出现,向 MyBatis-Plus 团队提交issue
  4. 在新项目中优先使用方案二的写法

🔗 相关链接