接着昨天的Mybatis扩展——IDaoTemplate接口。

  扩展9:批量执行

1、明确什么是批量执行

  首先说明一下,这里的批量执行不是利用<foreach>标签生成一长串的sql字符串——这并不是真正的JDBC批量执行,我这里所说的批量是指在内核调用JDBC的addBatch、executeBatch等方法来实现的。类似下面的示例:

 private void batchUpdate(Connection conn) throws SQLException {
PreparedStatement ps = null;
try{
String sql = " INSERT INTO BF_PARAM_ENUM_DATA "
+ " (PARAM_CODE,DATA_CODE,DATA_TEXT,DATA_PARAM,SEQNO,DES) "
+ " VALUES(?,?,?,?,?,?) ";
ps = conn.prepareStatement(sql);
for(int i = 0; i < 10; i++){
String random = RandomStringUtils.randomAlphabetic(8);
ps.setString(1, "TEST");//PARAM_CODE
ps.setString(2, random);//DATA_CODE
ps.setString(3, "数据" + random);//DATA_TEXT
ps.setString(4, "参数" + random);//DATA_PARAM
ps.setInt(5, i);//SEQNO
ps.setString(6, "");//MEMO
ps.addBatch();
}
int[] rs = ps.executeBatch();
System.out.print("batch insert : ");
for(int r : rs){
System.out.print(r+",");
}
System.out.println();
}finally{
try{
ps.close();
}catch(Exception e){}
}
}

2、批量执行的API  

  明白了批量执行的含义,接着看批量执行的API,再看一次IDaoTemplate接口中批量执行相关方法:

/**
* 执行批量:一个SQL执行多次
* @param sqlId SQL-ID
* @param parameters 参数对象数组
* @return 批量执行的影响记录数组
*/
public int[] executeBatch(String sqlId, List<?> parameters); /**
* 执行批量:一次执行多个SQL
* @param sqlIds 要执行的一组SQL-ID
* @return 批量执行的影响记录数组
*/
public int[] executeBatch(List<String> sqlIds); /**
* 执行批量:一次执行多个SQL
* @param sqlIds 要执行的一组SQL-ID
* @param parameters 参数对象数组
* @return 批量执行的影响记录数组
*/
public int[] executeBatch(List<String> sqlIds, List<?> parameters);

  简单的理解,批量执行就是需要执行一组操作,要么是相同SQL不同的参数,要么就是不同的SQL(参数相同或不同都可以)。至于这些接口怎么实现,都比较简单,根据SqlSessionFactory,创建批量执行的会话,大概如下:

this.batchSqlSession = new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);

然后和普通会话一样去执行update/insert/delete等操作,完了再调用批量会话的flushBatch方法返回结果即可。

这里有几个问题:

  • 批量执行的事务:批量执行怎么保证事务,是否通过添加Transactional注解即可?事实上,事务注解也只是一个注解,它本身不会对程序运行起任何影响,只有解析这个注解的程序,根据注解属性执行不同的业务逻辑,才会真正体现注解的作用。而另外一方面,Spring注解必须要求调用方法是容器管理的Bean方法,而IDaoTemplate接口的实现类,并不一定是Spring容器中的bean。因此,这里通过事务注解并不能生效,而需要使用编程式事务。相关代码大致如下:
 SqlSession batchSqlSession = getExecuteSqlSession();
PlatformTransactionManager txManager = this.getTransactinManager(dataSource);
if(null == txManager){
for(int i = 0, s = sqlIds.size(); i < s; i++){
batchSqlSession.update(SqlManager.getExecuteSqlId(sqlIds.get(i)), parameters==null?null : parameters.get(i));
}
List<BatchResult> r = batchSqlSession.flushStatements();
return resolveBatchResult(r);
}else{
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
for(int i = 0, s = sqlIds.size(); i < s; i++){
batchSqlSession.update(SqlManager.getExecuteSqlId(sqlIds.get(i)), parameters==null?null : parameters.get(i));
}
List<BatchResult> r = batchSqlSession.flushStatements();
txManager.commit(status);
return resolveBatchResult(r);
} catch (Throwable e) {
txManager.rollback(status);
throw Throw.createRuntimeException(e);
}
}
  • 执行方式的混合:如果在一个服务方法中,既有一般方式的dao访问,也有批量执行的dao访问,同时还处于一个事务中。由于Mybatis自身的限制,不能在同一个事务中切换执行方法,因此会抛出异常。那怎么办呢?我是利用ThreadLocal变量保存当前线程是否开启了批量执行模式,然后提供了如下三个管理方法作为批量执行的支持接口:

3、批量执行模式管理API

/**
* 打开批量执行模式
*/
public void openBatchType(); /**
* 恢复打开批量执行模式之前的执行模式
*/
public void resetBatchType(); /**
* 获取批量执行结果
* @return
*/
public int[] flushBatch();

这样,在前面提到的情况下,可以在服务方法开始,就调用openBatchType打开批量执行方式,然后依次执行各sql脚本,调用flushBatch()获取批量执行结果,在finally快再将当前线程的执行方式切换为调用openBatchType方法之前的执行方式。

  批量执行先说到这里,下一次再结合Dao接口的方法签名、Dao接口的自动代理子类等详细说明怎么使用自动代理调用批量执行。

   扩展10:merge

  在实际业务中,常常会有存在更新、不存在插入的数据库操作——merge,这种操作在Oracle数据库中可以直接利用SQL语法去更新,但是这种方法并不通用,更好的方法就是在Java中添加这个接口方法,但是添加接口方法也面临一个问题:怎么保证事务性?

  其实在看过前面的批量执行的事务处理之后,就没什么秘密可言了,类似的使用编程式事务就可以了。

  遗憾的是——由于平台组评审过于谨慎,这个接口并没有添加到IDaoTemplate中:

/**
* 存在更新、不存在插入
* @param insertSqlId 插入的SQL-ID
* @param updateSqlId 更新的SQL-ID
* @param parameter 参数对象
* @return 影响的记录条数
*/
public int merge(String insertSqlId, String updateSqlId, Object parameter);

  类似于merge,还可进一步做更多的扩展,只是通用性比较低,这里举一个例子来说明一下:

/**
* 根据条件执行不同sql
* <p>
* <ul>
* <li> 将参数对象parameter作为根对象,对条件表达式caseExpression求值
* <li> 根据求值结果,从sqlId映射中查找对应的sqlId,如果没有找到,就返回默认的sqlId
* <li> 根据计算的sqlId和参数对象,执行数据库操作,并返回结果
* </ul>
* </p>
* @param caseExpression 条件表达式,可为OGNL/SpEL
* @param sqlIdMapping sqlId映射
* @param defaultSqlId 默认的sqlId
* @param parameter 参数对象
* @return 影响的记录条数
*/
public int switchExecute(String caseExpression, Map<String, String> sqlIdMapping, String defaultSqlId, Object parameter);

  今天到此为止。

Java EE开发平台随手记4——Mybatis扩展3的更多相关文章

  1. Java EE开发平台随手记3——Mybatis扩展2

    忙里偷闲,继续上周的话题,记录Mybatis的扩展. 扩展5:设置默认的返回结果类型 大家知道,在Mybatis的sql-mapper配置文件中,我们需要给<select>元素添加resu ...

  2. Java EE开发平台随手记2——Mybatis扩展1

    今天来记录一下对Mybatis的扩展,版本是3.3.0,是和Spring集成使用,mybatis-spring集成包的版本是1.2.3,如果使用maven,如下配置: <properties&g ...

  3. Java EE开发平台随手记6——Mybatis扩展4

    这篇博客中来说一下对Mybatis动态代理接口方式的扩展,对于Mybatis动态代理接口不熟悉的朋友,可以参考前一篇博客,或者研读Mybatis源码. 扩展11:动态代理接口扩展 我们知道,真正在My ...

  4. Java EE开发平台随手记5——Mybatis动态代理接口方式的原生用法

    为了说明后续的Mybatis扩展,插播一篇广告,先来简要说明一下Mybatis的一种原生用法,不过先声明:下面说的只是Mybatis的其中一种用法,如需要更深入了解Mybatis,请参考官方文档,或者 ...

  5. Java EE开发平台随手记1

    过完春节以来,一直在负责搭建公司的新Java EE开发平台,所谓新平台,其实并不是什么新技术,不过是将目前业界较为流行的框架整合在一起,做一些简单的封装和扩展,让开发人员更加易用. 和之前负责具体的项 ...

  6. Java EE开发课外事务管理平台

    Java EE开发课外事务管理平台 演示地址:https://ganquanzhong.top/edu 说明文档 一.系统需求 目前课外兴趣培训学校众多,完善,但是针对课外兴趣培训学校教务和人事管理信 ...

  7. Java EE开发环境——MyEclipse2017破解 和 Tomcat服务器配置

    Java EE开发,我们可以搭建如下开发环境: 底层运行环境:jdk 和 jre. Web服务器:Tomcat 后台数据库:SQL Server 可视化集成开发环境:MyEclipse Java EE ...

  8. JEECG 3.7.1 版本发布,企业级JAVA快速开发平台

    JEECG 3.7.1 版本发布,企业级JAVA快速开发平台 ---------------------------------------- Version:  Jeecg_3.7.1项 目:   ...

  9. JEECG 4.0 版本发布,JAVA快速开发平台

    JEECG 4.0 版本发布,系统全面优化升级,更快,更稳定!         导读                               ⊙平台性能优化,系统更稳定,速度闪电般提升      ...

随机推荐

  1. yeoman(转)

    前言有一种技术可以提高我们的工作效率,可以让我们专心做我们擅长的事,可以屏蔽复杂性,可以规范我们的架构和我们的代码,可以让我们的享受编程的乐趣.Yeoman可以做到. 很多年以前,rails刚刚出世, ...

  2. 大文件下载控件(down2)-示例更新-Xproer.HttpDownloader

    版权所有 2009-2016 荆门泽优软件有限公司 保留所有权利 官方网站:http://www.ncmem.com/ 产品首页:http://www.ncmem.com/webapp/down2/i ...

  3. [UCSD白板题 ]Small Fibonacci Number

    Problem Introduction The Fibonacci numbers are defined as follows: \(F_0=0\), \(F_1=1\),and \(F_i=F_ ...

  4. 异或链表(XOR linked list)

    异或链表(Xor Linked List)也是一种链式存储结构,它可以降低空间复杂度达到和双向链表一样目的,任何一个节点可以方便的访问它的前驱节点和后继结点.可以参阅wiki 普通的双向链表 clas ...

  5. ORA-12705问题解决过程

    最近开发C#加ORACLE的程序,就有一台电脑连接的时候报错误 ORA-12705: Cannot access NLS data files or invalid environment speci ...

  6. 有关google的小问题

    从本周的开始,突然发现自己的浏览器打不开google了,我的默认浏览器是qq的,不过使用的也是google搜索.刚开始我以为是浏览器中毒了,就重新下了一个,结果还是同样的情况,而且我使用搜狗或者百度的 ...

  7. springMVC中一个controller多个方法

    web.xml文件: <?xml version="1.0" encoding="UTF-8"?><web-app version=" ...

  8. Percona Server 5.6.13-61.0 首个 GA 版本发布

    Percona Server 5.6 的首个 GA 版本发布了,版本号是 5.6.13-61.0 ,该版本基于 MySQL 5.6.13 改进内容包括: New Features: Percona S ...

  9. 轻量级MVC框架:Nancy学习

    一.认识Nancy 今天听讲关于Nancy框架的培训,被Nancy的易用性所吸引.故晚上回来梳理了一下知识. 什么是Nancy呢?如标题所述,Nancy是一个轻量级的独立的框架: Nancy 是一个轻 ...

  10. 可在广域网部署运行的QQ高仿版 -- GG叽叽V2.4,增加远程协助、桌面共享功能(源码)

    QQ的远程协助.或者说桌面共享是一个非常实用的功能,所以,2.4版本的GG复制了它,而且,GG增强了桌面共享的功能,它可以允许指定要共享桌面的区域,这样,对方就只能看到指定区域的桌面,这对节省流量会非 ...