MyBatis 批量提交 - BATCH

很多人在用 MyBatis 或者 通用 Mapper 时,经常会问有没有批量插入和批量更新的方法。

实际上许多时候没必要用 <foreach> 去实现特别复杂的批量操作。直接通过 MyBatis 的 BATCH 方式执行增删改方法即可。

下面是一个批量用法的例子:

@Autowired
private SqlSessionFactory sqlSessionFactory;

@Transactional(rollbackFor = Exception.class)
@Override
public void batchTest() {
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
    CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
    List<Country> countries = mapper.selectAll();
    for (int i = 0; i < countries.size(); i++) {
        Country country = countries.get(i);
        country.setCountryname(country.getCountryname() + "Test");
        mapper.updateByPrimaryKey(country);
        //每 50 条提交一次
        if((i + 1) % 50 == 0){
            sqlSession.flushStatements();
        }
    }
    sqlSession.flushStatements();
}

在上面例子中,在 Service 中直接注入了 SqlSessionFactory,通过下面方法获取了一个可以批量提交的 SqlSession

SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);

后续通过 SqlSession 直接执行方法,或者获取的 Mapper 接口,都使用的批量提交方式。

上述代码执行过程中输出的日志如下:

DEBUG - Creating new transaction with name [com.isea533.mybatis.service.impl.CountryServiceImpl.batchTest]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
DEBUG - Acquired Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@752c11a2] for JDBC transaction
DEBUG - Switching JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@752c11a2] to manual commit
DEBUG - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@752c11a2] will be managed by Spring
DEBUG - ==>  Preparing: SELECT Id,countryname,countrycode FROM country 
DEBUG - ==> Parameters: 
DEBUG - <==      Total: 183
DEBUG - ==>  Preparing: UPDATE country SET Id = Id,countryname = ?,countrycode = ? WHERE Id = ? 
DEBUG - ==> Parameters: AngolaTest(String), AO(String), 1(Integer)
DEBUG - ==> Parameters: AfghanistanTest(String), AF(String), 2(Integer)
DEBUG - ==> Parameters: AlbaniaTest(String), AL(String), 3(Integer)
==========================================
...省略中间部分参数
==========================================
DEBUG - ==> Parameters: EthiopiaTest(String), ET(String), 50(Integer)
DEBUG - ==>  Preparing: UPDATE country SET Id = Id,countryname = ?,countrycode = ? WHERE Id = ? 
DEBUG - ==> Parameters: FijiTest(String), FJ(String), 51(Integer)
DEBUG - ==> Parameters: FinlandTest(String), FI(String), 52(Integer)
==========================================
...省略中间部分参数
==========================================
DEBUG - ==> Parameters: MadagascarTest(String), MG(String), 98(Integer)
DEBUG - ==> Parameters: MalawiTest(String), MW(String), 99(Integer)
DEBUG - ==> Parameters: MalaysiaTest(String), MY(String), 100(Integer)
DEBUG - ==>  Preparing: UPDATE country SET Id = Id,countryname = ?,countrycode = ? WHERE Id = ? 
DEBUG - ==> Parameters: MaldivesTest(String), MV(String), 101(Integer)
DEBUG - ==> Parameters: MaliTest(String), ML(String), 102(Integer)
==========================================
...省略中间部分参数
==========================================
DEBUG - ==> Parameters: South AfricaTest(String), ZA(String), 149(Integer)
DEBUG - ==> Parameters: SpainTest(String), ES(String), 150(Integer)
DEBUG - ==>  Preparing: UPDATE country SET Id = Id,countryname = ?,countrycode = ? WHERE Id = ? 
DEBUG - ==> Parameters: Sri LankaTest(String), LK(String), 151(Integer)
DEBUG - ==> Parameters: St.LuciaTest(String), LC(String), 152(Integer)
==========================================
...省略中间部分参数
==========================================
DEBUG - ==> Parameters: ZaireTest(String), ZR(String), 182(Integer)
DEBUG - ==> Parameters: ZambiaTest(String), ZM(String), 183(Integer)
==========================================
下面事务自动提交
==========================================
DEBUG - Initiating transaction commit
DEBUG - Committing JDBC transaction on Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@752c11a2]
DEBUG - Releasing JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@752c11a2] after transaction
DEBUG - Returning JDBC Connection to DataSource

注意事项

1. 事务

由于在 Spring 集成的情况下,事务连接由 Spring 管理(SpringManagedTransaction),所以这里不需要手动关闭 sqlSession,在这里手动提交(commit)或者回滚(rollback)也是无效的。

2. 批量提交

批量提交只能应用于 insert, update, delete。

并且在批量提交使用时,如果在操作同一SQL时中间插入了其他数据库操作,就会让批量提交方式变成普通的执行方式,所以在使用批量提交时,要控制好 SQL 执行顺序。

2021-8-25 补充说明

回复中很多人在问,要不要手动关闭 sqlSession,文中说的不严谨,不完全正确。

  1. 当你添加 @Transactional 注解时,Spring 会自动帮你关闭连接,因此不需要手动关闭。

  2. 当没有使用该注解时,必须手动关闭连接。

大多数连接池的的连接关闭操作实际上是释放连接,释放后就可以让其他请求使用,如果所有连接都被占用而没有释放时,就会抛出异常。

  • 15
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 21
    评论
MyBatis 中进行批量提交有多种方法可以使用。以下是其中两种常用的方法: 1. 使用 JDBC 的批处理功能: ```java try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) { YourMapper mapper = sqlSession.getMapper(YourMapper.class); List<YourEntity> entityList = ... // 要批量插入或更新的实体列表 for (YourEntity entity : entityList) { mapper.insertOrUpdate(entity); // 调用插入或更新的方法 } sqlSession.commit(); // 执行批量提交 } ``` 在上述代码中,通过将 `SqlSession` 的执行器类型设置为 `BATCH`,可以开启批处理功能。然后,使用循环来依次调用插入或更新的方法,最后通过 `sqlSession.commit()` 进行批量提交。 2. 使用 MyBatis 提供的批量操作方法: ```java try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) { YourMapper mapper = sqlSession.getMapper(YourMapper.class); List<YourEntity> entityList = ... // 要批量插入或更新的实体列表 mapper.insertOrUpdateBatch(entityList); // 调用批量插入或更新的方法 sqlSession.commit(); // 执行批量提交 } ``` 在上述代码中,通过编写自定义的 `YourMapper` 接口,并在其中定义批量插入或更新的方法,如 `insertOrUpdateBatch`。然后,直接调用该方法传入实体列表,最后通过 `sqlSession.commit()` 进行批量提交。 需要注意的是,批量提交的效率可能会受到数据库和网络等因素的影响,具体的性能表现可能因环境而异。此外,使用批量提交时需要注意数据库事务的边界和正确的错误处理,以确保数据的一致性和操作的可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

isea533

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值