首页 > 其他分享 >ibatis 批处理

ibatis 批处理

时间:2023-06-04 18:35:27浏览次数:45  
标签:iBatis 事务 批处理 Spring replyList ibatis sqlMapClient

Ibatis中进行批量操作

 

iBatis整理——iBatis批处理实现(Spring环境)


最近做一个小项目,用到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.   
3. try {  
4. // 开始批处理  
5.         sqlMapClient.startBatch();  
6.   
7. for (Reply reply: replyList) {  
8. // 插入操作  
9. "Reply.create", reply);  
10.         }  
11. // 执行批处理  
12.         sqlMapClient.executeBatch();  
13.   
14. catch (Exception e) {  
15.         e.printStackTrace();  
16.     }  
17. }

这是基于iBatis的最基本实现,如果你一步一步debug,你会发现:其实,数据库已经执行了插入操作! 

因此,除了这两个核心方法外,你还需要开启事务支持。否则,上述代码只不过是个空架子! 


2.基于事务的iBatis的基本实现 

事务处理: 

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



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

Java代码 

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

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.   
6. try {  
7. // 开始事务  
8.             sqlMapClient.startTransaction();  
9. // 开始批处理  
10.             sqlMapClient.startBatch();  
11. for (Reply reply : replyList) {  
12. // 插入操作  
13. "Reply.create", reply);  
14.             }  
15.   
16. // 执行批处理  
17.             sqlMapClient.executeBatch();  
18. // 提交事务 交给Spring统一控制  
19. // sqlMapClient.commitTransaction();  
20.   
21. catch (Exception e) {  
22.             e.printStackTrace();  
23. finally {    
24. try {  
25. // 结束事务  
26.                 sqlMapClient.endTransaction();  
27. catch (SQLException e) {  
28.                              e.printStackTrace();  
29.                          }  
30.         }    
31.     }  
32. }

注意使用同一个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. new SqlMapClientCallback() {  
5. // 实现回调接口  
6. public Object doInSqlMapClient(SqlMapExecutor executor)  
7. throws SQLException {  
8. // 开始批处理  
9.             executor.startBatch();  
10. for (Reply reply : replyList) {  
11. // 插入操作  
12. "Reply.create", reply);  
13.   
14.             }  
15. // 执行批处理  
16.             executor.executeBatch();  
17.   
18. return null;  
19.   
20.         }  
21.     });  
22.   
23. }

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

引用

public void create(final List<Reply> replyList)

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

 

简述: 

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

http://michael-softtech.iteye.com/blog/620433

 

     最近遇到这样一个客户需求:需要向数据库里面一次插入几万条数据。系统的Persistence层用的是ibatis,

事务是通过spring管理。之前都是少量数据的操作,所以都是按照以下方式插入的:

 

 

1. class Service extends
2. {  
3. public void
4. {  
5.   getSqlMapClientTemplate().insert(..);  
6.     
7. }  
8.   
9. }

 

   但是数据量大时,速度奇慢。于是找时间读了一下ibatis的源码,终于发现了问题所在,记录如下:

 

   首先,过跟踪代码,发现sql的相关操作都有这样一个入口:

 


1. public

 

      上面的session是SqlMapSession的一个实例,而SqlMapSession继承了SqlMapExecutor接口,实际上以上的代码最终还是通过SqlMapExecutor的对应方法来实现(比如:session.insert(..)).

      于是继续追踪SqlMapSession的实现类:SqlMapSessionImpl。发现这个类的所有JDBC操作都是通过代理类SqlMapExecutorDelegate来实现的(这个代理类比SqlExecutor多了事务管理的配置:有一个TransactionManager)。这个代理类在每个单独的操作时,都先有这样一条语句:

 

 

1.  trans = getTransaction(session);  
2. null;

1. trans = autoStartTransaction(session, autoStart, trans);

    上述代码通过判断sutoStart来决定是不是开启一个事务。而autoStart是通过判断当前是不是已经有打开的事务

     来赋值的。那么就可以理解了:如果当前操作没有在事务下面,那么自动开启(取出)一个事务;如果已经有了事务,那么  直接使用当前事务。如果要进行批量操作,那么就必须在调用之前开启一个事务。所以就简单了:

 

1. public Object operate(final List<CardInfo> cardsToAdd, final List<AcctInfo> acctsToAdd, final List<AcctInfo> acctsToUpdate) throws
2.        
3. this.getSqlMapClientTemplate().execute(new
4. public
5.              {  
6.        
7. try{  
8.      getSqlMapClient().startTransaction();  
9.      executor.startBatch();...

   后面的startBatch语句是通过使用jdbc的批处理来提高效率。这样就能顺利执行同一个事务下的批量操作了(注意:如果在批量startBatch之前没有开启事务,批处理是无效的)。

标签:iBatis,事务,批处理,Spring,replyList,ibatis,sqlMapClient
From: https://blog.51cto.com/u_16120380/6411583

相关文章

  • Eclipse的iBatis插件
    mybatiseditor[[color=red]EditorsupportforMyBatisandiBatisinEclipse[/color]][url]https://code.google.com/a/eclipselabs.org/p/mybatiseditor/[/url]InstallationYouuseoneofthefollowingmethodstoinstallMyBatisEditor:Ecl......
  • 测试最终版ibatis
    1. 代码  51com.powernode.godbatis.pojoUserpackagecom.powernode.godbatis.pojo;//这是一个pojo用来测试我们的最终版godbatis的51publicclassUser{privateStringid;privateStringname;privateStringage;publicUser(Stringid,String......
  • 借助 mkcert 和批处理命令生成局域网证书
    借助 mkcert和批处理命令生成局域网证书自动获取ipv4,一键生成很方便cd/d%~dp0ipconfig|find"IPv4">ipv4set/pa=<ipv4delipv4for/f"tokens=2delims=:"%%ain("%a%")do(seta=%%a)mkcert.exelocalhost127.0.0.7::1%a%delcert.pem......
  • java List分批处理
    1packagecom.example.demo;2importcom.google.common.collect.Lists;3importjava.util.ArrayList;4importjava.util.List;5publicclassTest{6publicstaticvoidmain(String[]args){7List<Integer>list=newArrayList<......
  • Windows通过使用批处理.bat脚本文件修改DNS值
    在公司内网有自己的DNS服务器,但是在使用某些软件时又经常需要特定的DNS地址,每次切换都非常麻烦,所以写了个.bat批处理脚本文件方便切换,如果是修改IP等信息做些修改后同样可以使用。@echooff:startecho1:设置DNS为手动2:设置DNS为自动set/pvar=请选择if%var%==1gotoop......
  • windows与linux批处理脚本
    有一个windows下的bat脚本,希望丢到linux下去执行。主要是有一些字符要修改1.文件目录一个是‘\’,一个是‘/’2.使用./命令调用可执行文件3.使用vim编辑器,先输入:ff(fileformat的缩写),会显示文件是dos格式,输入:ff=unix,改为unix格式 ......
  • com.gitHub.pageHelper.PageHelper cannot be cast to org.apache.ibatis.pluin.Inter
    可能是因为版本冲突问题PageHelper5之前与之后是配置文件有发生变化,下面这个是使用pageHelper5.1.18jar包导入。使用PageHelper分页插件(使用spring+分页插件的方式)结果忘记把mybatis的分页插件和依赖去除,结果导致排错很久(怀疑是版本冲突的问题)附上正确用法:pom文件:<dependency......
  • 【转】【批处理】以管理员运行时修正当前路径
    转自:https://www.cnblogs.com/heroius/p/13600404.html在win7或更高版本windows系统中,使用管理员权限运行bat文件时,默认的当前路径(%CD%)被设置为C:\windows\system32。若脚本中使用了相对路径,那么运行将不正常。要解决此问题,在bat脚本的最前写入以下两行:@setlocalenableexte......
  • 批处理延时启动的几个方法
    [b]方法一:ping[/b]缺点:时间精度为1秒,不够精确@[email protected]>nulstartgdh.txt[b]方法二:vbsstart/wait[/b]缺点:生成临时文件优点:时间精度为0.001秒,精度高@echooffechowscript.sleep5000>sleep.vbsstart/waitsleep.vb......
  • 批处理和数据库连接池
    1. 批处理  8381.1 基本介绍1. 当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。2. JDBC的批量处理语句包括 下面方法:addBatch():添加需要批量处理的SQL语句或参数executeBa......