有的时候,我们需要一次性插入很多的数据或者一次性更新、删除很多的数据,那么为了提高效率,我们需要使用批处理来完成。以下将讨论Mybatis+Spring如何使用批处理。
首先应该知道Mybatis是Ibatis的升级版,比Ibatis性能更好,这是我采用Mybatis的原因。
Ibatis是支持批处理的:
- public void batchAddExamlog(List examlogList) throws SQLException{
- SqlMapClient smc=this.getSqlMapClient();
- try {
- smc.startTransaction();
- smc.startBatch();
- for (Iterator iter = examlogList.iterator(); iter.hasNext();) {
- Examlog log = (Examlog) iter.next();
- smc.update("insertExamlog", log);
- }
- smc.executeBatch();
- }finally{
- smc.commitTransaction();
- smc.endTransaction();
- }
- }
Mybatis接口实现批处理:
sessionFactory.openSession(ExecutorType.BATCH,true);//得到session,用于批量update
以上两种,他们都可以实现批处理。
但是当 Mybatis + Spring集成,且由Spring控制事务时,Mybatis这种批处理是不能使用的。
因为sessionFactory.openSession(ExecutorTypetype);方法会创建一个新的数据库连接,该连接不受Spring控制,将导致Spring的事务控制失效,它无法利用与当前线程绑定的session。
再看其他方式:
1、Mybatis主配置文件中,加入下面代码:
<configuration>
<settings>
<setting name="defaultExecutorType" value="BATCH"/>
</settings>
</configuration>
-- 这是个总配置,所有操作都会生效,在任何一个事务中做的更改,在事务结束时提交,该事务内无法读取自己的操作结果。
-- 它会导致所有方法 insert 无法返回id,update/delete 无法得到影响行数,所以、这个全局设置并不好。
2、配合(1)使用SqlSessionUtils.getSqlSession(sessionFactory).commit();
-- 虽然数据在事务内提交了,但是依然无法获得自增id
3、mapper文件中使用foreach标签拼装语句
-- 但是sql语句有长度限制,小数据量可以(当然也可以从数据库设置sql最长限制)。
4、获得当前连接,使用jdbc进行批处理操作。
-- 这也不好,sql需要写在其他地方,不能写在Mapper文件中。
5、从Spring上下文中,实例化两个SqlSessionTemplate,一个使用批处理方式,一个不使用批处理,程序中适时而用。
-- 无法获得自增id,且一个事务中不能同时使用两个SqlSessionTemplate。
6、从源代码,扩展自己的批处理实现。
1、BatchExecutor类的public List<BatchResult> doFlushStatements() throws SQLException方法最终执行批量操作,它将返回影响信息。
2、BatchExecutor.doFlushStatements() 方法在 Executor.commit() 方法中被调用。
3、Executor.commit() 在 SqlSession 中调用。
4、SqlSessionFactory 负责创建 SqlSession。
扩展SqlSessionFactory 创建我们定义的 MySqlSession,MySqlSession 最终可以调用到BatchExecutor.doFlushStatements() 获得影响结果
-- 这种方式需要扩展源码。
总结了几种方式,大家在项目中看情况使用吧。