mybatis使用lamda风格的批量更新(^_^)

本文介绍了Mybatis在批量操作时遇到的问题,如SQL过长导致的执行错误,以及如何使用Java8的Lambda表达式进行批量更新的优化,通过创建工具类简化代码,提高代码的可读性和复用性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mybatis批量操作

常用的做法如下代码所示:

// UserDao.java
/**
* 批量插入
*/
int batchInsert(@Param("users") List<User> users);
// UserDao.xml
   <insert id="batchInsert">
       INSERT INTO user (name,password) VALUES
       <foreach collection="users" item="user" index="index" separator=",">
           (#{user.name},#{user.password})
       </foreach>
   </insert>

但是,这样有个影藏的bug:当user集合超过一定数量,会导致动态拼接的sql过长而导致执行报错。并且,批量更新就不能使用这种形式了。

使用mybatis批量提交方式

// Mapper.xml
<insert id="insertName">
 		insert into names (name) values (#{value})
</insert>
// java code
List<String> names = new ArrayList<String>();
names.add("Fred");
names.add("Barney");
names.add("Betty");
names.add("Wilma");
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH,false);
try {
 		NameMapper mapper = sqlSession.getMapper(NameMapper.class);
 		for (String name : names) {
   		mapper.insertName(name);
 		}
 		sqlSession.commit();
} finally {
 		sqlSession.close();
}

这种java代码形式的批量操作更加通用且直观。但是需要自己管理sqlsession,这部分自我管理sqlsession的代码不但容易忘记(特别是finally中的sqlsession.close),而且违反了DRY原则,代码也显得冗长。

这里需要注意的是:自我管理sqlsession需要看一下源代码分析

public interface SqlSessionFactory {

  SqlSession openSession();

  SqlSession openSession(boolean autoCommit);
  SqlSession openSession(Connection connection);
  SqlSession openSession(TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType);
  SqlSession openSession(ExecutorType execType, boolean autoCommit);
  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
  SqlSession openSession(ExecutorType execType, Connection connection);

  Configuration getConfiguration();

}

可以观察到主要有四种参数类型,分别是 
- Connection connection 
- ExecutorType execType 
- TransactionIsolationLevel level 
- boolean autoCommit

官方文档中对这些参数也有详细的解释:

SqlSessionFactory 有六个方法可以用来创建 SqlSession 实例。通常来说,如何决定是你 选择下面这些方法时: 
Transaction (事务): 你想为 session 使用事务或者使用自动提交(通常意味着很多 数据库和/或 JDBC 驱动没有事务)? 
Connection (连接): 你想 MyBatis 获得来自配置的数据源的连接还是提供你自己 
Execution (执行): 你想 MyBatis 复用预处理语句和/或批量更新语句(包括插入和 删除)?

所以根据需求选择即可,由于我们要做的事情是批量insert,所以我们选择SqlSession openSession(ExecutorType execType, boolean autoCommit)

 

使用java8 lambda改造

首先对于sqlsession的资源管理可以使用java7的特性,try-with-resources管理。例如以下代码:

List<String> names = new ArrayList<String>();
names.add("Fred");
names.add("Barney");
names.add("Betty");
names.add("Wilma");
        //这里使用了try-with-resource
      try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH,false)) { //在try条件
          NameMapper mapper = sqlSession.getMapper(NameMapper.class);
			for (String name : names) {
  			mapper.insertName(name);
			}
          sqlSession.commit();
      } catch (Exception e) {
          logger.error("批量操作失败", e);
      }

然而,获取sqlsession和sql.commit等部分仍然是重复代码。调用者可能并不关心这些实现细节。

将批量操作独立为一个工具类,并使用java8 lambda改造:

/**
    * MyBatis 批量操作
    *
	 * @author jaryle
	 * @since 2016-05-31 09:17
    */
   @Component
   public class MyBatisBatch {
   
       private static final Logger logger = LoggerFactory.getLogger(MyBatisBatch.class);
   
       @Autowired
       private SqlSessionFactory sqlSessionFactory;
   
       public <T> void doBatch(Class<T> daoClass, Consumer<T> consumer){
           Objects.requireNonNull(consumer);
           if (sqlSessionFactory == null) {
               logger.error("无法获取mybatis sqlSessionFactory,请检查mybatis配置");
               throw XExceptionFactory.create("mybatis配置错误"));
           }
           try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH,false)) {
               T mapper = sqlSession.getMapper(daoClass);
               consumer.accept(mapper);
               sqlSession.commit();
           } catch (Exception e) {
               logger.error("批量操作失败", e);
               throw XExceptionFactory.create("批量操作失败");
           }
       }

使用示例:

 List<Long> userIds = new ArrayList<>();
   userIds.add(1L);
   userIds.add(2L);
   userIds.add(3L);
myBatisBatch.doBatch(UserDao.class, userDao ->
           userIds.forEach(userId -> userDao.insert(userId))
   );

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值