MyBatis 动态 SQL 分块处理 IN
子句语法解析
痛点
oracle 11g 只能in
1000个条件,大数据量无法处理
功能说明
用于解决数据库 IN
子句参数数量限制问题(如 Oracle 的 1000 元素限制),通过动态分块生成多组 IN
条件。
完整代码示例
<if test="piids != null and piids.size > 0">
AND (t0.processinstid IN
<trim suffixOverrides=" OR t0.processinstid IN()">
<foreach collection="piids" item="item" index="index" open="(" close=")">
<if test="index != 0">
<choose>
<when test="index % 1000 == 999">) OR t0.processinstid IN (</when>
<otherwise>,</otherwise>
</choose>
</if>
#{item}
</foreach>
</trim>
)
</if>
语法逐层解析
- 外层条件判断
<if test="piids != null and piids.size > 0">
- trim 标签清理
<trim suffixOverrides=" OR t0.processinstid IN()">
解决的问题:消除最后一块可能残留的无效语句
机制:自动删除结尾匹配的指定字符串 - foreach 分块逻辑
<foreach collection="piids" item="item" index="index" open="(" close=")">
分块规则
<choose>
<when test="index % 1000 == 999">) OR t0.processinstid IN (</when>
<otherwise>,</otherwise>
</choose>
分块策略:
每 1000 个元素 分块(索引从0开始计算)
index % 1000 == 999 ➔ 第1000个元素时触发分块
连接方式:
同块元素用 , 连接
分块时用 ) OR t0.processinstid IN ( 连接
数据库适配对照表
数据库 | IN 列表限制 | 调整方案 |
---|---|---|
Oracle | 1000 | 保持现有代码:index % 1000 == 999 (索引从0开始,第1000个元素时分块) |
SQL Server | 2100 | 修改为:index % 2100 == 2099 (索引达到2099时触发分块) |
MySQL | 无硬性限制 | 移除分块逻辑,直接逗号连接所有元素 |
PostgreSQL | 无硬性限制 | 移除分块逻辑,直接逗号连接所有元素 |
补充说明:
-
Oracle/SQL Server 分块逻辑
- 因数据库对
IN
子句的表达式数量有严格限制,需通过模运算 (%
) 控制分块节点。 - 公式:
index % N == (N-1)
,其中N
为数据库允许的最大值(Oracle=1000,SQL Server=2100)。
- 因数据库对
-
MySQL/PostgreSQL 优化
- 可直接简化为:
<foreach collection="piids" item="item" open="(" close=")" separator=","> #{item} </foreach>
- 可直接简化为: