
使用Mybatis框架批量插入的3种方法:多次调用insert方法、foreach标签、batch模式,下面分别详解@mikechen
多次调用insert插入
这种方式理解起来最简单,一个单独的插入接口,业务上循环调用即可。
1.增加Mapper接口
@Mapper
public interface InsertMapper {
    /**
     * 写入
     * @param po
     * @return
     */
    int save(@Param("po") MoneyPo po);
}
2.对应XML配置
<resultMap id="BaseResultMap" type="com.mikechen.mybatis.entity.UserPo">
    <id column="id" property="id" jdbcType="INTEGER"/>
    <result column="name" property="name" jdbcType="VARCHAR"/>
    <result column="money" property="money" jdbcType="INTEGER"/>
    <result column="is_deleted" property="isDeleted" jdbcType="TINYINT"/>
    <result column="create_at" property="createAt" jdbcType="TIMESTAMP"/>
    <result column="update_at" property="updateAt" jdbcType="TIMESTAMP"/>
</resultMap>
<insert id="save" parameterType="com.mikechen.mybatis.entity.MoneyPo" useGeneratedKeys="true" keyProperty="po.id">
  INSERT INTO `user` (`name`, `money`, `is_deleted`)
  VALUES
(#{po.name}, #{po.money}, #{po.isDeleted});
</insert>
3.业务逻辑代码
private UserPo buildPo() {
    UserPO po = new UserPo();
    po.setName("mikechen");
    po.setMoney((long) random.nextInt(12343));
    po.setIsDeleted(0);
    return po;
}
public void testBatchInsert() {
    for (int i = 0; i < 10; i++) {
        moneyInsertMapper.save(buildPo());
    }
}
这种方式的优点就是简单直观,缺点就是db交互次数多,开销大。
foreach插入
这种方法是依靠 MyBatis 中的 foreach 标签,将数据拼接成一条原生的 insert 语句一次性执行的。
1.增加插入接口
@Mapper
public interface UserMapper extends BaseMapper<User> {
    boolean saveBatchByNative(List<User> list);
}
2.创建UserMapper.xml 文件
使用 foreach 标签拼接 SQL,如下所示:
<?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.demo.mapper.UserMapper">
    <insert id="saveBatchByNative">
        INSERT INTO `USER`(`NAME`,`PASSWORD`) VALUES
        <foreach collection="list" separator="," item="item">
            (#{item.name},#{item.password})
        </foreach>
    </insert>
</mapper>
3.业务逻辑实现
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {
    @Autowired
    private UserMapper userMapper;
    public boolean saveBatchByNative(List<User> list) {
        return userMapper.saveBatchByNative(list);
    }
}
使用sql批量插入的方式,优点是db交互次数少,在插入数量可控时,相比于前者开销更小。
缺点也很明显,当一次插入的数量太多时,组装的sql既有可能直接超过了db的限制无法执行了。
batch模式插入
针对上面做一个简单的优化,使用BATCH批处理模式,实现会话复用,避免每次请求都重新维护一个链接导致额外开销。
使用如下:
@Autowired
    private SqlSessionFactory sqlSessionFactory;
    //通过Mybatis batch模式批量插入群组人员
    //开启BATCH批量模式
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
    TIdReGroupUserMapper tIdReGroupUserMapper = sqlSession.getMapper(TIdReGroupUserMapper.class);
    int addNum = 0;
    try {
            TIdReGroupUser tIdReGroupUser = new TIdReGroupUser();
            for (int i = 0; i < userIds.length; i++) {
                tIdReGroupUser.setId(UUID.randomUUID().toString());
                tIdReGroupUser.setGroupId(groupId);
                tIdReGroupUser.setUserId(userIds[i]);
                addNum += tIdReGroupUserMapper.insert(tIdReGroupUser);
            }
            sqlSession.commit();
        }finally {
            closeSqlSession(sqlSession, sqlSessionFactory);
        }
}
使用Mybatis的batch模式进行批量插入,数据量较大的场景中后者效率更高。
关于mikechen
mikechen睿哥,10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。