MyBatis 批处理两种实现模式

  1. oracle数据库绑定变量太多,有可能引起数据库宕机,现在要求数据库批量操作不能使用 insert into xxx select 1 from dual union all select 2 from dual 方式。
  2. 如果for循环单个操作性能不太好,所以尽量改为使用mybatis原生的批处理。
  3. 影子表方案等有对sql做解析扩展的情况,如果sql太大,解析起来也会有影响
  4. insert into xxx select 1 from dual union all select 2 from dual 方式 prepareStatement,不同参数,解析都不一样,可重用性不高,每次都需要解析,影响性能

 一、sqlSession直接执行方式
        考拉很多老工程写法都是 dao里获取sqlSession,再做具体处理。该种前人已实现,直接盗过来贴代码了。如下:
  • 其中getGenericSqlSessionFactory(),获取的是就是配置文件中配置的SqlSessionFactoryBean,通过手动创建sqlSession,指定BATCH模式。sqlSession作为回调方法process的入参,业务实现指定具体操作。
  • ListUtils是个分页工具类,防止一次提交太多
  • 在批处理方案上添加了事务注解,保证批处理操作在一个事务。默认事务传播属性为REDUIRED, 也保证跟外层事务是同一个事务。
@Repository("batchExecutorDaoImpl")
public class BatchExecutorDaoImpl extends BaseDaoImpl {

@Transactional(value = "txManager", rollbackFor = Exception.class)
public <T> void batch(List<T> dataList, int batchSize, final SingleProcessor<T> processor) {
final SqlSession session = getGenericSqlSessionFactory().openSession(ExecutorType.BATCH);
ListSplitUtil.split(dataList, batchSize, new ListSplitUtil.Processer<T>() {
@Override
public void process(List<T> pageIdList) {
for (T data : pageIdList) {
processor.process(session, data);
}
session.commit();
}
});
}

public static interface SingleProcessor<T> {
public void process(SqlSession sqlSession, T data);
}
}

二、MyBatis Mapper方式
      当前很多新功能都改用Mapper方式(基础sql动态生成,Mapper.java跟Mapper.xml一一对应,代码可读性更高)。
      mapper方式通过配置文件也是可以的,但是配置范围太大,不够灵活。所以也是提供工具类来使用。如下:
  • 同样的,需要把sqlSessionFactory注进来使用; 通过手动创建sqlSession,指定BATCH模式
  • 事务也开启
  • doBatch 需要指定Mapper接口类, 通过sqlSession.getMapper(cls)获取Mapper代理,作为SingleProcessor. process的参数
  • 业务实现直接拿到Mapper代理执行具体操作
@Component
public class BatchExecutor4MapperManager {

@Resource(name = "oracleSqlSessionFactory")
private SqlSessionFactory sqlSessionFactory;

public interface SingleProcessor<T, M> {
void process(M mapper, T data);
}

@Transactional(value = "txManager", rollbackFor = Exception.class)
public <T, M> void doBatch(List<T> dataList, final Class<M> cls,
final SingleProcessor<T, M> processor) {
final SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
        final M mapper = sqlSession.getMapper(cls);
ListSplitUtil.split(dataList, 100, new ListSplitUtil.Processer<T>() {
@Override
public void process(List<T> pageDataList) {
for (T data : pageDataList) {
processor.process(mapper, data);
}
sqlSession.commit();
}
});
}
}

本文来自网易实践者社区,经作者张晓单授权发布。