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

mybatis批量操作

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

// UserDao.java
/**
* 批量插入
*/
int batchInsert(@Param("users") List users);
// UserDao.xml
   
       INSERT INTO user (name,password) VALUES
       
           (#{user.name},#{user.password})
       
   

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

使用mybatis批量提交方式

// Mapper.xml

 		insert into names (name) values (#{value})

// java code
List names = new ArrayList();
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 names = new ArrayList();
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  void doBatch(Class daoClass, Consumer 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 userIds = new ArrayList<>();
   userIds.add(1L);
   userIds.add(2L);
   userIds.add(3L);
myBatisBatch.doBatch(UserDao.class, userDao ->
           userIds.forEach(userId -> userDao.insert(userId))
   );

 

你可能感兴趣的:(mybatis)