推荐用动态SQL的<foreach>标签配合IN子句实现MyBatis批量删除,需用@Param注解传入非空List,并在XML中用<if>判断ids非空以避免IN()错误,超大批量时应分批或改用逻辑删除。

MyBatis 批量删除数据,推荐用 动态 SQL 的 <foreach> 标签 配合 IN 子句实现,避免硬编码、SQL 注入和参数超限问题。核心是把 ID 列表传入,由 MyBatis 自动拼接为 WHERE id IN (?, ?, ?) 形式。
传入 List 或 List 参数
Mapper 接口方法接收一个非空集合(如 List<long></long>),作为删除条件:
void deleteByIds(@Param("ids") List<Long> ids);
注意必须使用 @Param 注解命名参数,否则 <foreach> 无法识别。
XML 中用 <foreach> 构建 IN 条件
在 Mapper XML 中写动态 SQL:
立即学习“Java免费学习笔记(深入)”;
<delete id="deleteByIds">
DELETE FROM user WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
-
collection:对应
@Param("ids")的值名 -
item:循环中每个元素的别名(可任意取,如
id) - open / close:包裹整个 IN 括号,防止空集合时报错
- separator:元素间逗号分隔
处理空集合或 null 的安全写法
直接执行空集合会生成 IN () 导致 SQL 报错。加一层 <if> 判断更健壮:
<delete id="deleteByIds">
<if test="ids != null and ids.size() > 0">
DELETE FROM user WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</if>
</delete>
此时若传入空列表或 null,整个 SQL 不执行(MyBatis 返回 0 行影响),业务层可据此判断是否跳过操作。
替代方案:用主键范围或逻辑删除
当 ID 数量极大(如上万),IN 子句可能触发数据库参数限制(如 MySQL max_allowed_packet)或性能下降。这时可考虑:
- 分批调用(每批 500~1000 条)
- 改用时间/状态等范围条件(如
WHERE create_time < ?) - 用逻辑删除(UPDATE SET deleted = 1)替代物理删除
不复杂但容易忽略细节:务必校验输入集合非 null、非空,并配合数据库事务控制一致性。


















