1. MyBatis批量操作基础入门
如果你正在使用MyBatis进行数据库操作,批量处理绝对是必须掌握的技能。想象一下,你有一万条数据要插入数据库,如果一条一条执行,不仅效率低下,还会给数据库造成巨大压力。而批量操作就像把货物装进集装箱一次性运输,效率能提升几十倍甚至上百倍。
MyBatis提供了强大的foreach标签来实现批量操作,我们先来看看它的基本属性:
- item:循环体中的具体对象,相当于for循环中的临时变量
- index:当前迭代的序号(从0开始)
- collection:要遍历的集合,这是最重要的属性
- open:整个循环体开始时的字符串
- separator:每次循环之间的分隔符
- close:整个循环体结束时的字符串
collection属性的取值有讲究,根据传入参数类型不同而不同:
- 单参数是List时,值为"list"
- 单参数是数组时,值为"array"
- 多个参数时,需要封装成Map
这里有个新手常踩的坑:当参数是List时,collection写成了"collection"或者参数名,导致报错。记住,单List参数时固定写"list",单数组参数时固定写"array"。
2. 批量插入实战详解
批量插入是最常用的场景,比如导入Excel数据、初始化数据等。先看Mapper接口定义:
public interface EmployeeMapper {
int batchInsert(List<Employee> employees);
}
对应的XML配置:
<insert id="batchInsert" parameterType="java.util.List">
INSERT INTO t_employee(name, age, department)
VALUES
<foreach collection="list" item="emp" separator=",">
(#{emp.name}, #{emp.age}, #{emp.department})
</foreach>
</insert>
这里有几个优化点需要注意:
- 如果数据量特别大(比如超过1万条),建议分批插入,每批500-1000条
- MySQL默认限制SQL长度,可能需要调整max_allowed_packet参数
- 返回的int值是插入的行数,但批量插入时不同数据库表现可能不同
实际测试发现,批量插入1万条数据,单条插入需要30秒,而批量插入仅需0.5秒,性能提升60倍!
3. 批量更新的两种高效方案
批量更新比插入复杂,主要有两种实现方式:
3.1 多语句拼接方式
<update id="batchUpdate" parameterType="java.util.List">
<foreach collection="list" item="emp" separator=";">
UPDATE t_employee
SET name=#{emp.name}, age=#{emp.age}
WHERE id=#{emp.id}
</foreach>
</update>
这种方式需要MySQL连接字符串添加allowMultiQueries=true参数,否则会报语法错误。它的优点是直观简单,缺点是SQL语句较长时性能会下降。
3.2 CASE WHEN条件更新
<update id="batchUpdate" parameterType="java.util.List">
UPDATE t_employee
SET
name = CASE id
<foreach collection="list" item="emp">
WHEN #{emp.id} THEN #{emp.name}
</foreach>
END,
age = CASE id
<foreach collection="list" item="emp">
WHEN #{emp.id} THEN #{emp.age}
</foreach>
END
WHERE id IN
<foreach collection="list" item="emp" open="(" separator="," close=")">
#{emp.id}
</foreach>
</update>
这种方案只需要一条SQL语句,执行效率更高。我在项目中实测,更新1000条数据,CASE WHEN方式比多语句方式快3倍左右。
4. 批量删除的三种参数类型处理
批量删除支持List、数组和Map三种参数类型,这里分别说明:
4.1 List参数方式
<delete id="batchDelete" parameterType="java.util.List">
DELETE FROM t_employee
WHERE id IN
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
4.2 数组参数方式
<delete id="batchDelete" parameterType="java.util.Arrays">
DELETE FROM t_employee
WHERE id IN
<foreach collection="array" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
4.3 Map参数方式
<delete id="batchDelete" parameterType="java.util.Map">
DELETE FROM t_employee
WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
注意Map方式需要在接口中使用@Param指定key:
int batchDelete(@Param("ids") Map<String, Integer> paramMap);
5. 批量查询与性能优化
批量查询的实现与删除类似,主要区别在于结果映射:
<select id="batchQuery" resultType="com.example.Employee">
SELECT * FROM t_employee
WHERE id IN
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
对于大数据量批量操作,我有几个优化建议:
- 合理设置batchSize,建议500-1000条一批
- 考虑使用ExecutorType.BATCH模式
- 监控SQL执行时间,超过1秒的考虑优化
- 对于超大批量操作,可以考虑使用存储过程
曾经我在处理一个数据迁移任务时,刚开始批量插入10万条数据需要5分钟,通过调整batchSize和启用BATCH模式,最终优化到20秒完成。
152



被折叠的 条评论
为什么被折叠?



