MyBatis 批量添加(动态 SQL)
·
在日常开发中,批量添加数据是高频需求 —— 比起单条循环插入,批量添加能大幅减少数据库交互次数,提升数据插入效率。MyBatis 通过动态 SQL 的<foreach>标签,就能轻松实现批量插入功能。本文结合实战场景,从核心原理到具体实现,一步步教你掌握 MyBatis 批量添加的全流程,新手也能快速上手。
一、批量添加的核心逻辑
MyBatis 批量添加的本质是将多条插入语句合并为单条多值 SQL,语法格式如下:
INSERT INTO user (name, age, email)
VALUES (值1, 值2, 值3), (值4, 值5, 值6), (值7, 值8, 值9);
核心关键有两点:
- 入参类型:用
List集合包裹实体对象(如List<User>),统一传递多条数据; - 动态 SQL:通过
<foreach>标签遍历集合,自动生成多个(值列表),并用逗号分隔。
对比单条插入,批量添加能减少 SQL 解析次数和网络通信开销,数据量越大,性能优势越明显。
二、实战准备:实体类规范
首先需确保实体类符合 MyBatis 映射要求,避免因配置不当导致数据插入失败:
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
private Integer age;
private String email;
public User() {}
public User(String name, Integer age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
2. 核心注意点
- 主键
id自增时,插入语句中需排除该字段,避免手动赋值覆盖自增逻辑; - 必须同时提供无参和带参构造器:无参构造器供 MyBatis 实例化,带参构造器方便快速创建对象;
- 字段使用包装类(如
Integer而非int),避免 null 值无法表达的问题。
三、核心实现:Mapper 接口 + 动态 SQL
1. Mapper 接口定义
批量添加的入参为List<User>,需通过@Param注解指定集合别名(便于 XML 中引用):
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserMapper {
// 单条插入
int insertUser(User user);
// 批量插入
int batchInsertUsers(@Param("users") List<User> users);
}
2. XML 动态 SQL 编写
核心是通过<foreach>标签遍历集合,生成多值插入语句,注意避免多余括号嵌套:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
<insert id="batchInsertUsers" parameterType="java.util.List">
INSERT INTO user (name, age, email)
VALUES
<foreach collection="users"
item="user"
separator=",">
(#{user.name}, #{user.age}, #{user.email})
</foreach>
</insert>
<insert id="insertUser" parameterType="com.example.pojo.User">
INSERT INTO user (name, age, email)
VALUES (#{name}, #{age}, #{email})
</insert>
</mapper>
四、测试验证:批量插入实战
编写测试类,创建多个 User 对象并批量插入,注意添加事务注解保证数据提交:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-mybatis.xml")
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
@Transactional
public void testBatchInsertUsers() {
User user1 = new User("张三", 20, "zhangsan@test.com");
User user2 = new User("李四", 22, "lisi@test.com");
User user3 = new User("王五", 25, "wangwu@test.com");
List<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
int rows = userMapper.batchInsertUsers(userList);
System.out.println("批量插入成功,影响行数:" + rows);
}
}
2. 测试结果验证
运行测试后,查询数据库user表,会发现 3 条数据已同时插入,主键 id 自动生成,证明批量添加功能生效。
五、生产级注意事项
- 事务控制:批量插入必须加
@Transactional注解,避免部分数据插入成功、部分失败导致数据不一致; - 数据量控制:单次批量插入不宜超过 1000 条,数据量过大时可分批次插入(如每 500 条提交一次),避免 SQL 过长或事务过大;
- 数据库兼容:本文语法适用于 MySQL,Oracle 需改用
INSERT ALL语法(如INSERT ALL INTO user VALUES(...) INTO user VALUES(...) SELECT 1 FROM DUAL); - 性能优化:MySQL 连接 URL 添加
rewriteBatchedStatements=true,开启 JDBC 批量优化,进一步提升插入效率; - 参数校验:批量插入前需校验集合非空、元素字段非空,避免因单条数据非法导致整批插入失败。
六、总结
MyBatis 批量添加的核心是「List入参 +<foreach>动态 SQL」,步骤简单但需注意细节:
- 实体类需满足无参构造器、序列化等规范;
- XML 中
<foreach>标签需正确配置集合别名和分隔符,避免括号嵌套错误; - 测试和生产环境需开启事务,控制批量数据量。
掌握这套方法后,无论是日常批量导入数据,还是高并发场景下的数据批量存储,都能高效应对。相比单条插入,批量添加能减少 90% 以上的数据库交互开销,是提升系统性能的关键技巧之一。
更多推荐



所有评论(0)