最近做一个小项目,用到Spring+iBatis。突然遇到一个很久远,却很实在的问题:在Spring下怎么使用iBatis的批处理实现?

大概是太久没有写Dao了,这部分真的忘得太干净了。

从4个层面分析这部分实现: 

  1. iBatis的基本实现
  2. 基于事务的iBatis的基本实现
  3. 基于事务的Spring+iBatis实现
  4. 基于回调方式的Spring+iBatis实现

1.iBatis的基本实现 
iBatis通过SqlMapClient提供了一组方法用于批处理实现: 

  1. startBatch() 开始批处理
  2. executeBatch() 执行批处理

代码如下: 

Java代码 
  1. public void create(List<Reply> replyList) {
  2. try {
  3. // 开始批处理
  4. sqlMapClient.startBatch();
  5. for (Reply reply: replyList) {
  6. // 插入操作
  7. sqlMapClient.insert("Reply.create", reply);
  8. }
  9. // 执行批处理
  10. sqlMapClient.executeBatch();
  11. } catch (Exception e) {
  12. e.printStackTrace();
  13. }
  14. }

这是基于iBatis的最基本实现,如果你一步一步debug,你会发现:其实,数据库已经执行了插入操作! 
因此,除了这两个核心方法外,你还需要开启事务支持。否则,上述代码只不过是个空架子!

2.基于事务的iBatis的基本实现 
事务处理: 

  1. startTransaction() 开始事务
  2. commitTransaction() 提交事务
  3. endTransaction() 结束事务

我们以insert操作为例,把它们结合到一起: 

Java代码 
  1. public void create(List<Reply> replyList) {
  2. try {
  3. // 开始事务
  4. sqlMapClient.startTransaction();
  5. // 开始批处理
  6. sqlMapClient.startBatch();
  7. for (Reply reply: replyList) {
  8. // 插入操作
  9. sqlMapClient.insert("Reply.create", reply);
  10. }
  11. // 执行批处理
  12. sqlMapClient.executeBatch();
  13. // 提交事务
  14. sqlMapClient.commitTransaction();
  15. } catch (Exception e) {
  16. e.printStackTrace();
  17. } finally {
  18. try {
  19. // 结束事务
  20. sqlMapClient.endTransaction();
  21. } catch (SQLException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. }

replyList是一个List,要把这个List插入到数据库,就需要经过这三个步骤: 

  1. 开始批处理 startBatch()
  2. 插入      insert()
  3. 执行批处理 executeBatch()

如果要在Spring+iBatis中进行批处理实现,需要注意使用同一个sqlMapClient!同时,将提交事务的工作交给Spring统一处理!

3.基于事务的Spring+iBatis实现 

Java代码 
  1. public void create(List<Reply> replyList) {
  2. if (!CollectionUtils.isEmpty(replyList)) {
  3. // 注意使用同一个SqlMapClient会话
  4. SqlMapClient sqlMapClient = sqlMapClientTemplate.getSqlMapClient();
  5. try {
  6. // 开始事务
  7. sqlMapClient.startTransaction();
  8. // 开始批处理
  9. sqlMapClient.startBatch();
  10. for (Reply reply : replyList) {
  11. // 插入操作
  12. sqlMapClient.insert("Reply.create", reply);
  13. }
  14. // 执行批处理
  15. sqlMapClient.executeBatch();
  16. // 提交事务 交给Spring统一控制
  17. // sqlMapClient.commitTransaction();
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. } finally {
  21. try {
  22. // 结束事务
  23. sqlMapClient.endTransaction();
  24. } catch (SQLException e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. }
  29. }

注意使用同一个sqlMapClient: 
SqlMapClient sqlMapClient = sqlMapClientTemplate.getSqlMapClient(); 
如果直接sqlMapClientTemplate执行insert()方法,将会造成异常!

想想,还有什么问题?其实问题很明显,虽然解决了批处理实现的问题,却造成了事务代码入侵的新问题。 这么做,有点恶心! 
除此之外,异常的处理也很恶心,不能够简单的包装为 DataAccessException 就无法被Spring当作统一的数据库操作异常做处理。 

4.基于回调方式的Spring+iBatis实现 
如果观察过Spring的源代码,你一定知道,Spring为了保持事务统一控制,在实现ORM框架时通常都采用了回调模式,从而避免了事务代码入侵的可能! 
修改后的代码如下: 

Java代码 
  1. @SuppressWarnings("unchecked")
  2. public void create(final List<Reply> replyList) {
  3. // 执行回调
  4. sqlMapClientTemplate.execute(new SqlMapClientCallback() {
  5. // 实现回调接口
  6. public Object doInSqlMapClient(SqlMapExecutor executor)
  7. throws SQLException {
  8. // 开始批处理
  9. executor.startBatch();
  10. for (Reply reply : replyList) {
  11. // 插入操作
  12. executor.insert("Reply.create", reply);
  13. }
  14. // 执行批处理
  15. executor.executeBatch();
  16. return null;
  17. }
  18. });
  19. }

注意,待遍历的参数replyList需要加入final标识!即,待遍历对象不能修改! 

引用
public void create(final List<Reply> replyList)

这样做,就将事务处理的控制权完全交给了Spring! 
简述: 

  1. SqlMapClientCallback 回调接口
  2. doInSqlMapClient(SqlMapExecutor executor) 回调实现方法
  3. DataAccessException 最终可能抛出的异常

通过上述修改,最终能够解决第三种实现方式中的种种不足!

Spring对iBatis提供的支持还是不够完善,即便是现在最新的Spring3.0.4。最开始,本打算用Spring3.0+iBatis3.0,结果Spring报错,说找不到“com.ibatis.xxxxx”完全是iBatis2.x的包路径!汗颜~ 还是Hibernate比较得宠!

ibatis实现批处理的更多相关文章

  1. ibatis的批处理

    (1)spring模式:尽管spring已经配置了事务,但以下代码中还是要设置事务,不然batch不会起作用;另外这里虽然设了一下事务处理,但对全局事务并不会造成影响;注:不启用事务将建立多次连接,这 ...

  2. Ibatis相关

    XML中的#和$的区别 http://shenzhenchufa.blog.51cto.com/730213/254561 poolMaximumActiveConnections和poolMaxim ...

  3. iBatis框架batch处理优化 (转)

    为什么要做batch处理        这个问题我就不解释了,因为我想你们肯定能比我解释的更好!如果你真的不知道,那就到Google上去搜索一下吧☻Oracle回滚段    这个问题偶也不很明白,只是 ...

  4. Spring Batch 批处理框架

    <Spring Batch 批处理框架>基本信息作者: 刘相 出版社:电子工业出版社ISBN:9787121252419上架时间:2015-1-24出版日期:2015 年2月开本:16开页 ...

  5. Ibatis学习总结6--使用 SQL Map API 编程

    SQL Map API 力求简洁.它为程序员提供 4 种功能:配置一个 SQL Map,执行 SQL update操作,执行查询语句以取得一个对象,以及执行查询语句以取得一个对象的 List. 配置  ...

  6. 图书简介:Spring Batch批处理框架

    大数据时代批处理利器,国内首度原创解析Spring Batch框架. 内容简介: <Spring Batch 批处理框架>全面.系统地介绍了批处理框架Spring Batch,通过详尽的实 ...

  7. ibatis框架的sqlmapclient接口

    SqlMapClient,是iBatis中的重要接口,这个接口涉及到对SQL映射的执行和批处理. 现在,就先了解它的对query开头方法的定义. 首先是 queryForList 方法: //指定SQ ...

  8. iBatis系列一

    XML iBatis可以使用xml来作为参数输入以及结果返回:这个功能的优势在于某些特定的场景:还有可以通过DOM方式来作为参数传递:但是这个方式应用的比较少,如果服务器是xml服务器可以采用这种方式 ...

  9. 使用 getNextException() 来检索已经过批处理的特定元素的异常。 ERRORCODE=-4228, SQLSTATE=null

    今天查询了一天发现的问题,用ibatis做批量操作时,报错: [非原子批处理出现故障]使用 getNextException() 来检索已经过批处理的特定元素的异常. ERRORCODE=-4228, ...

随机推荐

  1. python 中为什么不需要重载

    函数重载主要是为了解决两个问题. (1)可变参数类型. (2) 可变参数个数. 另外,一个基本的设计原则是,仅仅当两个函数除了参数类型和参数个数不同以外,其功能是完全相同的,此时才使用函数重载,如果两 ...

  2. 在定制工作项时,把“团队项目”作为变量获取生成版本信息

    有用户最近提出这个需求: 通过工作项定制,新增一个字段用以保存项目Bug的"影响版本"信息,但是需要从当前团队项目的服务器生成纪录中获取版本的选项,类似默认模板中的"发现 ...

  3. linux bash变量替换(# ## % %% / //)

    VAR=hahaha echo ${VAR#*h} # ahaha 从前向后匹配删除 VAR=hahaha echo ${VAR##*h} # a 贪婪模式,从前向后匹配删除所有 VAR=hahaha ...

  4. 手动编译安装lamp之php

    转自马哥教育讲课文档 三.编译安装php-5.4.8 1.解决依赖关系: 请配置好yum源(可以是本地系统光盘)后执行如下命令: # yum -y groupinstall "X Softw ...

  5. Ubuntu 12.04 Openssh 安装过程

    1.输入 apt-get install openssh-server 注意 出现依赖 需要使用 查看依赖是否需要,如果不需要可以直接删除,sudo apt-get remove XXXX 或者sud ...

  6. MySQL多线程备份工具mydumper 之 RDS外部实例迁移平台

    此文已由作者温正湖授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 1.Format_description_event问题: BINLOG ' kTXkUxMKAAAALQA ...

  7. gitlab中修改项目名称客户端修改方法

    如果gitlab项目名称已经修改,对于本地已经克隆下来的仓库,可以使用如下命令进行修改: git remote set-url origin 新的项目路径

  8. 【OCP-12c】CUUG 071题库考试原题及答案解析(22)

    5.choose the best answer Evaluate the following CREATE SEQUENCE statement: CREATE SEQUENCE seq1 STAR ...

  9. 设置、读取、删除cookie

    刚才用虚拟机当服务器,开了两个服务(端口号不同),发现同样的cookie:在别的网站下面没有发现该cookie.说明cookie只是对应相应的网站的(自己得出的结论) ---------------- ...

  10. java使用Redis2--保存对象

    Redis中并没有提供set(String key, Object obj)的方法,但提供了set(final byte[] key, final byte[] value) 的方法,可以通过把对象转 ...