Spring的AOP事务管理默认是针对unchecked exception回滚。

也就是默认对RuntimeException()异常极其子类进行事务回滚。

Exception作为基类,下面还分checked exception和unchecked exception。如果客户端可以通过其他的方法恢复异常,那么这种异

常就是checked exception;如果客户端对出现的这种异常无能为力,那么这种异常就是Unchecked exception;简单来说,继承于

RuntimeException的都是unchecked exception。

Error:
1.总是不可控制的(unchecked)
2.经常用来用于表示系统错误或低层资源的错误
3.如何可能的话,应该在系统级被捕捉

Exception:
1.可以是可被控制(checked) 或不可控制的(unchecked)
2.表示一个由程序员导致的错误
3.应该在应用程序级被处理

Java 中定义了两类异常:
1) Checked exception: 这类异常都是Exception的子类。异常的向上抛出机制进行处理,假如子类可能产生A异常,那么在父类中

也必须throws A异常。可能导致的问题:代码效率低,耦合度过高。
2) Unchecked exception: 这类异常都是RuntimeException的子类,虽然RuntimeException同样也是Exception的子类,但是它们是

非凡的,它们不能通过client code来试图解决,所以称为Unchecked exception 。

解决办法:

1.在针对事务的类中抛出RuntimeException异常,而不是抛出Exception。

2.在txAdive中增加rollback-for,里面写自己的exception,例如自己写的exception为

com.cn.untils.exception.***Exception

<tx:advice id="txAdvice" transaction-manager="transactionManager">
  <tx:attributes>
    <tx:method name="*" rollback-for="com.cn.untils.exception.***Exception"/>
  </tx:attributes>
</tx:advice>

或者

定义不会滚的异常

<tx:advice id="txAdvice">
   <tx:attributes>
      <tx:method name="update*" no-rollback-for="IOException"/>
      <tx:method name="*"/>
   </tx:attributes>
</tx:advice>

spring事务回滚.默认情况,unchecked异常,即运行时异常runntimeException回滚事务;checked异常,即Exception可try{}捕获的不会回滚.当然也可配置spring参数让其回滚.

 

 

试验方法:

写一个单元测试,调用一个service层方法(发生对数据库进行写操作的方法--insert、update、delete)即可.

试验过程:

定义一个service方法如下:

public SMSTiming createSMSTiming(SMSTiming smsTiming){

SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);

return s;

}

定义二个异常(先默认配置TestException为Spring事务回滚异常):

            publicclass MyTestException extends Exception

            publicclass TestException extends Exception

注意看下:每次这个方法的不同处(抛出的异常不同)。

 

测试1:

public SMSTiming createSMSTiming(SMSTiming smsTiming){

SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);

int i = 4/0; //人为产生异常(实际这里抛出了ArithmeticException运行异常)

return s;

}

测试1结果:会事务回滚----数据库中未插入新数据。

测试2:

public SMSTiming createSMSTiming(SMSTiming smsTiming) throws Exception{//受检异常(非运行异常)必须抛出

SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);

try{

int i = 4/0; //人为产生异常

}catch(Exception e){

thrownew Exception ("");//抛出Exception异常

}

return s;

}

测试2结果:不会事务回滚----数据库中插入新数据。

 

测试3:

public SMSTiming createSMSTiming(SMSTiming smsTiming) throws RuntimeException{//运行异常(非受检异常)可以不抛出

SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);

try{

int i = 4/0; //人为产生异常

}catch(Exception e){

thrownewRuntimeException("");//抛出RuntimeException异常

}

return s;

}

测试3结果:会事务回滚----数据库中未插入新数据

测试4:

public SMSTiming createSMSTiming(SMSTiming smsTiming) throws TestException{//受检异常(非运行异常)必须抛出

SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);

try{

int i = 4/0; //人为产生异常

}catch(Exception e){

thrownewTestException("");//抛出TestException异常

}

return s;

}

测试4结果:会事务回滚----数据库中未插入新数据。

测试5:

public SMSTiming createSMSTiming(SMSTiming smsTiming) throws MyTestException{//受检异常(非运行异常)必须抛出

SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);

try{

int i = 4/0; //人为产生异常

}catch(Exception e){

thrownewMyTestException("");//抛出MyTestException异常

}

return s;

}

 测试5结果:不会事务回滚----数据库中插入新数据。

 

测试6:

public SMSTiming createSMSTiming(SMSTiming smsTiming) throws MyTestException{//受检异常(非运行异常)必须抛出 (注意:此时spring指定配置此异常回滚)

SMSTiming s= this.getSmsTimingDAO().createSMSTiming(smsTiming);

try{

int i = 4/0; //人为产生异常

}catch(Exception e){

thrownewMyTestException("");//抛出MyTestException异常

}

return s;

}

 测试6结果:会事务回滚----数据库中未插入新数据。

 

 

试验总结:

测试1、测试3、测试4、测试6会进行事务回滚;测试2、测试5不会进行事务回滚。

为什么会这样?因为是异常的类型(受检异常、运行时异常)不同或使用了Spring的rollback-for配置。

 

测试1和测试3是因为抛出了运行时异常,会事务回滚。

测试4和测试5、测试6分别抛出受检异常TestException、MyTestException,那为什么测试4和测试6会事务回滚呢?

因为是我们在Spring事务配置中指定了此异常(指定rollback-for)。

最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了.......  
  为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志。但是这边情况来了,当这个方法异常时候 日志是打印了,但是加的事务却没有回滚。

例:  
   类似这样的方法不会回滚 (一个方法出错,另一个方法不会回滚) :

  1. if(userSave){
  2. try {
  3. userDao.save(user);
  4. userCapabilityQuotaDao.save(capabilityQuota);
  5. } catch (Exception e) {
  6. logger.info("能力开通接口,开户异常,异常信息:"+e);
  7. }
  8. }

下面的方法回滚(一个方法出错,另一个方法会回滚):

  1. if(userSave){
  2. try {
  3. userDao.save(user);
  4. userCapabilityQuotaDao.save(capabilityQuota);
  5. } catch (Exception e) {
  6. logger.info("能力开通接口,开户异常,异常信息:"+e);
  7. throw new RuntimeException();
  8. }
  9. }

或者:

  1. if(userSave){
  2. try {
  3. userDao.save(user);
  4. userCapabilityQuotaDao.save(capabilityQuota);
  5. } catch (Exception e) {
  6. logger.info("能力开通接口,开户异常,异常信息:"+e);
  7. TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  8. }
  9. }

为什么不会滚呢??是对Spring的事务机制就不明白。!! 
   默认spring事务只在发生未被捕获的 runtimeexcetpion时才回滚。  
   spring aop  异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获runtimeexception的异常,但可以通过  
    
配置来捕获特定的异常并回滚  
  换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion(),这样程序异常时才能被aop捕获进而回滚
  解决方案: 
  方案1.例如service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw new RuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异常并处理
  方案2.在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常(现在项目的做法)

 

Spring框架的事务基础架构代码将默认地  在抛出运行时和unchecked exceptions时才标识事务回滚。 也就是说,当抛出一个RuntimeException 或其子类例的实例时。(Errors 也一样 - 默认地 - 标识事务回滚。)从事务方法中抛出的Checked exceptions将  被标识进行事务回滚

Spring transaction事务 roll back各种回滚的更多相关文章

  1. sql事务(Transaction)用法介绍及回滚实例

    sql事务(Transaction)用法介绍及回滚实例 事务(Transaction)是并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位.通过事务, S ...

  2. MySql数据库事务正常提交,回滚失败

    问题:在初次练习Mysql数据库事务时,事务正常提交,但是在遇到异常应当回滚时,回滚失败. 代码如下: //2.更新操作. public void update(Connection conn, St ...

  3. SpringBoot统一异常处理后TX-LCN分布式事务无法捕获异常进行回滚

    通常我们使用SpringBoot都会进行统一异常处理,例如写一个BaseController,在BaseController里进行统一异常处理,然后其他的Controller都继承BaseContro ...

  4. Spring transaction事务之roll back回滚

    转载自:http://blog.csdn.net/lovejavaydj/article/details/7635848 试验方法: 写一个单元测试,调用一个service层方法(发生对数据库进行写操 ...

  5. spring @Transaction事务回滚失败

    今天客户提出一个新问题,出库一批商品,提示失败了,但是库存数量却减少了.看了一下代码一头雾水,我们的代码加了事物,且捕获异常. 经过调试代码发现就是两个原因导致的 第一.在当前方法的catch中处理了 ...

  6. spring事务不会进行回滚的情况

    if(userSave){ try { userDao.save(user); userCapabilityQuotaDao.save(capabilityQuota); } catch (Excep ...

  7. spring 事务控制 设置手动回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

    //假设这是一个service类的片段 try{ //出现异常 } catch (Exception e) { e.printStackTrace(); //设置手动回滚 TransactionAsp ...

  8. spring data jpa使用@Transactional注解开启事务后失败不回滚

    如题,在数据库批量操作方法上使用@Transactional注解,其中一条数据抛出异常了,却死活不回滚. 批量操作方法是公有的,spring也是默认支持事务的,排除代码层面问题,那么就看看数据库是否支 ...

  9. Spring+Junit,测试事务时,一直回滚

    研究了好长时间,都不知道原因,也不能解决. 控制台又没有报异常,但是就是一直回滚.注释掉spring声明式配置的代码,就能正确的更新数据. 从网上看了,别人的文章 http://blog.csdn.n ...

随机推荐

  1. C和C++的内存操作小贴士(一):const char*的内存释放问题

    C和C++的内存操作一直是困扰开发人员的老问题,基本概念相信老司机们都很清楚了,在这里就不做过多的描述了,只是把在实际开发中可能遇到的一些小问题的案例列举下,供大家参考.“C和C++的内存操作小贴士” ...

  2. 第一个shell程序

    前言:我为什么又来学习shell呢?因为这个轻量级的编程小脚本语言能够帮我处理一些基于linux的复杂手工工作.真是一言难尽,学会一门又来一门!! 看了2天这个教程,试着写了一个小脚本,没啥技术含量, ...

  3. 定制库到Maven本地资源库

    这里有2个案例,需要手动发出Maven命令包括一个 jar 到 Maven 的本地资源库. 要使用的 jar 不存在于 Maven 的中心储存库中. 您创建了一个自定义的 jar ,而另一个 Mave ...

  4. 创建Swing的步骤

    (1)导入Swing包 (2)选择界面风格 (3)设置顶层容器 (4)设置按钮和标签 (5)将组件放到容器上 (6)为组件增加边框 (7)处理事件 (8)辅助技术支持 package Com.MySw ...

  5. jQuery回调、递延对象总结

    jQuery回调.递延对象总结(上篇)—— jQuery.Callbacks jQuery回调.递延对象总结(中篇) —— 神奇的then方法 jQuery回调.递延对象总结(下篇) —— 解密jQu ...

  6. OpenOffice将MS docx转换成pdf文件偶数页眉不显示问题解决办法

    OpenOffice版本:4.0(Windows.Linux下测试都出现问题) MS Office版本:2007 问题描述 使用OpenOffice将MS的docx文件转换为pdf文件时,docx文件 ...

  7. Web打印控件Lodop实现证件套打

    第一次接触Lodop大概是在两年前了,那时候研究Lodop主要是为了验证它能不能实现打印时在不修改内容的前提下调整样式,结果是ok的,如今又一次接触它,是因为工作中需要使用它了,于是再一次碰面 Lod ...

  8. 前端Table数据导出Excel使用HSSFWorkbook(Java)

    一.实现原理: 1. 前端查询列表数据并渲染至table(<table>...</table>)表格 2. 表格html代码传输至后台 3. 后台把html转成Excel输出流 ...

  9. android代码规范和studio配置CodeStyle

    studio配置CodeStyle可以很好的帮助我们检测代码规范性,保持大家的代码统一,来看看怎么配置和使用吧 代码规范,自己公司的一套 代码规范 一.      简介 A.    目的 本文提供一整 ...

  10. [iOS]XCODE5升级之路

    1.Code Sign error:     解决方案:重新下载并安装Provisioning profile 2.错误:Undefined symbols for architecture armv ...