Spring声明式事务管理出错示例与解决之道(转载)
来源:百度文库 编辑:神马文学网 时间:2024/04/29 12:17:24
前言今天,发现了一个以前写的使用Spring声明式事务管理的程序爆出了数据库连接错误,感觉是非常典型的一个误用Spring声明式事务管理的例子,拿出来为大家点评一下。请先阅读我之前写的关于事务管理的文章:《事务管理最佳实践全面解析》, 《事务管理最佳实践多余的话之一“每次请求,一次数据库连接,一次事务”是不是金科玉律?》, 《事务管理最佳实践多余的话之二:Transaction后缀给声明式事务管理带来的好处》 Spring声明式事务管理出错示例这个应用程序是使用Spring管理的iBatis程序。事务使用了Spring的声明式事务管理。爆出了如下的错误:Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed at com.withub.wcms.manage.collectnews.systemNewsinfo.dao.WcmsSystemNewsinfoDao.add(WcmsSystemNewsinfoDao.java:50) at com.withub.wcms.manage.collectnews.systemNewsinfo.service.WcmsSystemNewsinfoService.saveOrUpdate(WcmsSystemNewsinfoService.java:103) at com.withub.wcms.manage.collectnews.systemNewsinfo.service.WcmsSystemNewsinfoService.formatRawInfoToHtml(WcmsSystemNewsinfoService.java:89) 可以看出,出现的错误是,Spring管理下的iBatis使用的数据库连接是只读的。而在DAO类的方法 中,却使用了修改数据库的iBatis方法。 源代码:WcmsSystemNewsinfoDao类的源代码就不列出来了。这个Dao类的add方法使用了iBatis的update方法,更新数据库数据。下面是WcmsSystemNewsinfoService类的部分相关调用方法的源代码:public String formatRawInfoToHtml(String infoRawId) throws Exception{ WcmsSystemNewsinfoRawModule wcmsSystemNewsinfoRawModule=new WcmsSystemNewsinfoRawModule(); wcmsSystemNewsinfoRawModule.setInfoId(infoRawId); //原表数据 wcmsSystemNewsinfoRawModule=this.getManageNewsinfoService().queryRawInfoById(wcmsSystemNewsinfoRawModule); WcmsSystemNewsinfoModule wcmsSystemNewsinfoModule=new WcmsSystemNewsinfoModule(); //目标表数据 BeanUtils.copyProperties(wcmsSystemNewsinfoModule, wcmsSystemNewsinfoRawModule); wcmsSystemNewsinfoModule.setInfoRawId(wcmsSystemNewsinfoRawModule.getInfoId()); wcmsSystemNewsinfoModule.setInfoId(null); returnthis.saveOrUpdate(wcmsSystemNewsinfoModule); } /** *需要把目标表Model信息保存在目标表中。如果该记录已存在,则更新,否则,新增! * *@parammodule *@throwsException */ public String saveOrUpdate(WcmsSystemNewsinfoModule module) throws Exception{ WcmsSystemNewsinfoModule loadModule=this.getWcmsSystemNewsinfoDao().selectWcmsSystemNewsinfoModuleByInfoRawId(module.getInfoRawId()); String infoId=null; if(loadModule==null){ //插入 infoId=this.getWcmsSystemNewsinfoDao().add(module); }else{ //更新 /** *更新 *1,找到主键条件 */ infoId=loadModule.getInfoId(); module.setInfoId(loadModule.getInfoId()); this.getWcmsSystemNewsinfoDao().updateProcessedInfo(module); } return infoId; } 源代码说明:WcmsSystemNewsinfoService类的formatRawInfoToHtml(String infoRawId)方法,根据传入的参数,准备好所需的数据,然后调用本类的saveOrUpdate(WcmsSystemNewsinfoModule module)方法。saveOrUpdate()方法,根据情况,调用WcmsSystemNewsinfoDao类的add或者update方法。 Spring事务配置文件一、事务配置抽象Bean声明 readOnly PROPAGATION_REQUIRED,-Exception PROPAGATION_REQUIRED,-Exception PROPAGATION_REQUIRED,-Exception PROPAGATION_REQUIRED,-Exception PROPAGATION_REQUIRED,-Exception PROPAGATION_REQUIRED,-Exception PROPAGATION_REQUIRED, readOnly,-Exception PROPAGATION_REQUIRED, -Exception 二、服务类的Spring声明式事务管理 错误解析错误的原因就在上面的Spring声明式事务里。执行WcmsSystemNewsinfoService类的formatRawInfoToHtml()方法时,会应用txProxyTemplate的配置,由于它的方法名与所有的特殊配置都不匹配,因此,会应用第一个声明式事务: readOnly 因此,SpringAOP创建了一个只读的数据库连接和事务。然后,调用WcmsSystemNewsinfoService类的saveOrUpdate()方法,也会查找上面的事务配置,匹配:PROPAGATION_REQUIRED,-Exception SpringAOP会去得到数据库连接和设置事务。由于在本地线程变量中已经找到了前面提供的只读连接,就会直接使用这个数据库连接,并在其上设置事务。最后,调用WcmsSystemNewsinfoDao类的add方法。由于使用的是只读连接,执行add方法中的update语句,就发生了上面的错误:Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed Spring真的能够管理一切吗?像上面这样的Spring事务配置和Service、Dao的写法,应当说是相当普遍的,我们认为Spring已经把数据库连接、事务、O-R映射等等管得妥妥当当了,不用我们再操心了,再理解事务了!真的如此吗?错!漠视数据库、漠视事务,我们的系统到底有多少类似的隐患?我们的业务服务类Service浪费了多少SPringAOP的帮助?降低了多少性能?Spring、EJB这样的声明式事务,确实大大方便了我们处理数据库连接和事务。但是,我们还是需要自己理解业务逻辑对数据库连接,对事务的需要!工具只能帮助我们解决我们认识到的问题,解决不了我们都没理解的问题。 不能再把一切扔给框架、容器、工具!首先理解你的业务逻辑,理解你要实现的功能,然后搞清楚框架、容器、工具会帮助我们做什么。只有理解了自己的业务逻辑,理解了自己的代码,理解了自己要用到的第三方代码,才能真正完美地实现我们需要的功能! 用我们的命名方法来重构上面的问题代码一、给Service类中的2个方法加上后缀名标识对事务的依赖 当然,Service接口相应的方法也要改变。/* (non-Javadoc) * @see com.withub.wcms.manage.collectnews.systemNewsinfo.service.IWcmsSystemNewsinfoService#formatRawInfoToHtml(java.lang.String) */ public String formatRawInfoToHtmlTransaction(String infoRawId) throws Exception{ WcmsSystemNewsinfoRawModule wcmsSystemNewsinfoRawModule=new WcmsSystemNewsinfoRawModule(); wcmsSystemNewsinfoRawModule.setInfoId(infoRawId); //原表数据 wcmsSystemNewsinfoRawModule=this.getManageNewsinfoService().queryRawInfoById(wcmsSystemNewsinfoRawModule); WcmsSystemNewsinfoModule wcmsSystemNewsinfoModule=new WcmsSystemNewsinfoModule(); //目标表数据 BeanUtils.copyProperties(wcmsSystemNewsinfoModule, wcmsSystemNewsinfoRawModule); wcmsSystemNewsinfoModule.setInfoRawId(wcmsSystemNewsinfoRawModule.getInfoId()); wcmsSystemNewsinfoModule.setInfoId(null); returnthis.saveOrUpdateDao(wcmsSystemNewsinfoModule); } /** *需要把目标表Model信息保存在目标表中。如果该记录已存在,则更新,否则,新增! * *@parammodule *@throwsException */ public String saveOrUpdateDao(WcmsSystemNewsinfoModule module) throws Exception{ WcmsSystemNewsinfoModule loadModule=this.getWcmsSystemNewsinfoDao().selectWcmsSystemNewsinfoModuleByInfoRawId(module.getInfoRawId()); String infoId=null; if(loadModule==null){ //插入 infoId=this.getWcmsSystemNewsinfoDao().add(module); }else{ //更新 /** *更新 *1,找到主键条件 */ infoId=loadModule.getInfoId(); module.setInfoId(loadModule.getInfoId()); this.getWcmsSystemNewsinfoDao().updateProcessedInfo(module); } return infoId; }这样,formatRawInfoToHtmlTransaction方法可以直接被最终用户调用。它将能够创建或得到数据库连接,管理事务,最后关闭数据库连接。而,saveOrUpdateDao方法,不能直接被最终用户调用。如果它需要数据库连接,它可以使用本地线程变量中保存的数据库连接。 二、修改Service类的声明式事务的配置文件 PROPAGATION_REQUIRED,-Exception 这里,重载了txProxyTemplate的声明式事务配置。我们只对Service类中的以Transaction结尾的方法,应用事务,在发生异常时,回滚。这样,Transaction方法直接或者间接调用的DAO接口中的方法,就可以使用本地线程变量中保存的由Transaction方法的AOP代理方法创建的数据库连接。数据库连接和事务被真正的摆平了!世界真美好!
Spring声明式事务管理出错示例与解决之道(转载)
全面分析 Spring 的编程式事务管理 及声明式事务管理
Struts2与Spring、Hibernate示例
Spring声明式处理
spring声明式事务
Spring的事务管理2.0与1.2.8的区别
Spring的事务管理2.0与1.2.8的区别 - JAVA AJAX C - Blo...
如何使用spring声明式事务
Struts2与Spring、Hibernate三者整合的过程示例*
Struts2与Spring Hibernate三者整合的过程示例
Struts2与Spring、Hibernate三者整合过程示例
spring的事务管理问题_rollback时机
spring aop alliance示例
Spring 中的数据源(转载)
Spring声明式事务策略-Spring-Java -JavaEye做最棒的软件开发交流社区
Spring事务管理 - Java - 课堂 - 话题 - 迟宏泽 - CSDN学生大本营...
Spring 事务管理高级应用难点剖析: 第 1 部分
Spring 事务管理高级应用难点剖析: 第 2 部分
Spring 事务管理高级应用难点剖析: 第 3 部分
Struts2与Spring、Hibernate三者整合的过程示例333
Struts2与Spring、Hibernate三者整合的过程示例4
spring 声明试事务代理
直销三人行:直销信息化解决之道中华管理在线(转载)
Spring 使用Properties配置文件(转载)