`

运用@Transactional,自己抛出异常时不会回滚的原因

阅读更多
一、 当你读这篇文章的时候,假如读者是在整合j2EE的三大框架式遇到这个问题,那应该就是下面这个问题:
   
    我记得当时我遇到这个问题的时候,是因为数据库的表,不支持事务!如果mysql不支持存储引擎,它将以MyISAM表创建表,这是非事务性表。一般修改成InnoDB.
 
    假如有兴趣了解 mysql中 " engine=innodb " 以及 " engine=innodb 和engine=myisam的区别 ",可以读读这篇文章,或许对读者有帮助:http://blog.sina.com.cn/s/blog_6ac4c6cb01018pb1.html
 
    可使用下述语句之一检查表的标类型: 
    SHOW TABLE STATUS LIKE 'tbl_name';
    SHOW CREATE TABLE tbl_name;
  使用下述语句,可检查mysqld服务器支持的存储引擎: 
   
    SHOW ENGINES;
 
    也可以使用下述语句,检查与你感兴趣的存储引擎有关的变量值: 

    SHOW VARIABLES LIKE 'have_%';

  例如,要想确定InnoDB存储引擎是否可用,可检查have_innodb变量的值。
 
 
 二 、假如读者不是上述情况,那请研读下面这段:
--------------------------------------------------------------------------------------------------
 
近日测试用例,发现这样一个现象:

在业务代码中,有如下两种情况,比如:
throw new RuntimeException("xxxxxxxxxxxx"); 事务回滚
throw new Exception("xxxxxxxxxxxx"); 事务没有回滚
 
自以为很了解事务,或许时间久远的缘故,没分析出来何故,遂查阅了下资料,写下了如下的内容,供参考:
 
1).Spring的AOP即声明式事务管理默认是针对unchecked exception回滚。也就是默认对RuntimeException()异常或是其子类进行事务回滚;checked异常,即Exception可try{}捕获的不会回滚,如果使用try-catch捕获抛出的unchecked异常后没有在catch块中采用页面硬编码的方式使用spring api对事务做显式的回滚,则事务不会回滚, “将异常捕获,并且在catch块中不对事务做显式提交=生吞掉异常” ,要想捕获非运行时异常则需要如下配置:
解决办法:
1.在针对事务的类中抛出RuntimeException异常,而不是抛出Exception。
2.在txAdive中增加rollback-for,里面写自己的exception,例如自己写的exception:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
   <tx:attributes>
     <tx:method name="*" rollback-for="com.cn.untils.exception.XyzException"/>
   </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>
 
2).spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行commit or rollback(Spring默认取决于是否抛出runtime异常).
 如果抛出runtime exception 并在你的业务方法中没有catch到的话,事务会回滚。 
 一般不需要在业务方法中catch异常,如果非要catch,在做完你想做的工作后(比如关闭文件等)一定要抛出runtime exception,否则spring会将你的操作commit,这样就会产生脏数据.所以你的catch代码是画蛇添足。
 
如:
try {  
    //bisiness logic code  
} catch(Exception e) {  
    //handle the exception  
}  
 由此可以推知,在spring中如果某个业务方法被一个 整个包裹起来,则这个业务方法也就等于脱离了spring事务的管理,因为没有任何异常会从业务方法中抛出!全被捕获并吞掉,导致spring异常抛出触发事务回滚策略失效。
 不过,如果在catch代码块中采用页面硬编码的方式使用spring api对事务做显式的回滚,这样写也未尝不可。
 
 3).基于注解的事务:
 Transactional的异常控制,默认是Check Exception 不回滚,unCheck Exception回滚
 如果配置了rollbackFor 和 noRollbackFor 且两个都是用同样的异常,那么遇到该异常,还是回滚
 rollbackFor 和noRollbackFor 配置也许不会含盖所有异常,对于遗漏的按照Check Exception 不回滚,unCheck Exception回滚

该博文转自:http://blog.sina.com.cn/s/blog_6ac4c6cb01018pbl.html
分享到:
评论

相关推荐

    Spring中@Transactional事务回滚(含实例

    1. **默认回滚规则**:如果在`@Transactional`方法中抛出未检查异常(继承自`RuntimeException`的异常)或者`Error`,Spring将自动回滚事务。 2. **非默认回滚规则**:对于受检异常(即没有继承自`RuntimeException`...

    后端 Java Spring Data Jpa @Transactional 介绍

    如果抛出了未检查异常或检查异常且在`@Transactional`注解中指定了可传播的异常类型,事务将被回滚。 例如,以下代码展示了如何在Spring Data JPA的Service层使用`@Transactional`: ```java @Service public ...

    Spring中的@Transactional事物回滚实例源码

    在这个例子中,`createUser`方法被标记为事务性的,如果在方法内部抛出未捕获的异常,Spring会自动回滚事务,确保数据一致性。 Spring事务管理的工作流程大致如下: 1. **AOP代理**:Spring使用AOP(面向切面编程)...

    浅谈Spring中@Transactional事务回滚及示例(附源码)

    浅谈Spring中@Transactional事务回滚及示例 @Transactional是Spring Framework中的一种事务管理机制,用于管理数据库事务。它可以使得数据库操作更加安全和可靠。本文将详细介绍@Transactional的使用场景、checked...

    什么情况会导致@Transactional事务失效?

    如果在方法内部捕获了所有异常并重新抛出,或者返回了错误代码而非抛出异常,事务可能不会按照预期进行回滚。 5. ** propagation 设置不当**:`@Transactional`的propagation属性决定了事务如何在方法间传播。如果...

    Spring @Transactional注解失效解决方案

    如果在没有事务的环境下被调用,容器抛出例外。 5. SUPPORTS:该方法在某个事务范围内被调用,则方法成为该事务的一部分。如果方法在该事务范围外被调用,该方法就在没有事务的环境下执行。 6. NEVER:该方法绝对不...

    spring的@Transactional注解详细用法1

    如果方法抛出异常,事务则会被回滚,以此确保事务的ACID(原子性、一致性、隔离性和持久性)特性。 在Spring中,事务管理器(如`DataSourceTransactionManager`)会确保每个事务都在一组相关操作之间保持一致。例如...

    spring 简单实例 事务回滚

    Spring默认只在遇到未检查异常时自动回滚事务,如果需要在特定检查异常下回滚,可以在`@Transactional`注解中指定`rollbackFor`属性。 5. 测试:创建一个测试类,模拟一个业务流程,使得在事务中发生异常,观察事务...

    Spring事务管理A方法内部调用B方法的回滚问题测试代码

    然而,如果`methodB`的异常没有被捕获并重新抛出,而是被忽略或者处理了,那么Spring可能无法检测到这个异常,从而不会回滚`methodA`的事务。因此,捕获并重新抛出异常是至关重要的,如示例代码所示。 此外,需要...

    注解实现声明式事务管理

    其他传播行为包括SUPPORTS(如果已有事务就支持,没有则不开启)、MANDATORY(必须存在事务,否则抛出异常)、REQUIRES_NEW(总是新建事务,如果已有事务则挂起)、NOT_SUPPORTED(不支持事务,如果已有事务则挂起)...

    Spring异常捕获且回滚事务解决方案

    如果我们想让 AOP 代理捕获异常,那么我们需要在方法中重新抛出异常,或者在 catch 语句中最后增加 throw new RuntimeException() 语句。 Spring 事务机制 在 Spring 中,事务机制是通过 TransactionManager 来...

    Spring事务管理只对出现运行期异常进行回滚

    Spring的事务管理默认策略是,只有当方法抛出运行时异常时,事务才会被回滚。这是因为运行时异常被认为是不可预见的,程序不应该继续执行。而如果抛出的是检查异常,Spring默认假设这是业务逻辑的一部分,因此不会...

    Transactional:Spring事务性Junit测试

    如果测试过程中没有抛出异常,那么在方法结束时事务会被提交;如果有异常发生,事务会自动回滚,保持数据的原貌。 在实际项目中,Transactional-master这个压缩包可能包含了整个测试项目的源码,包括Spring配置文件...

    SpringBoot的事务使用和回滚功能讲解.docx

    这种方法通常在捕获到异常后并且不重新抛出时使用,以确保事务不会因为方法的“成功”执行而提交。 5. **异常处理与事务回滚**: 在`try-catch`块中,如果捕获到一个`RuntimeException`但没有重新抛出,Spring将...

    spring注解式事务

    * noRollbackFor:抛出特定异常时不回滚事务 * rollbackForClassName:抛出特定异常类名时回滚事务 * noRollbackForClassName:抛出特定异常类名时不回滚事务 Spring框架提供了灵活的方式来管理事务,开发者可以...

    java-mybatis、springmvc 整合demo源码(druid-demo)

    如果捕获了异常并重新抛出,事务可能不会回滚。 在"druid-demo"这个项目中,通过分析源码,我们可以学习到如何处理这些问题,确保@Transactional注解在遇到异常时能够正确地管理事务。 最后,通过这个示例,我们...

    spring-控制事物回滚

    - 当方法抛出异常时,Spring会查找是否匹配`rollbackFor`或`noRollbackFor`属性中的异常类型,从而决定是否回滚事务。异常匹配是精确匹配,不考虑异常的子类。 7. **Test_jdbc_tran**: - 压缩包中的`Test_jdbc_...

    Spring事务之7种传播行1

    如果`methodB`被单独调用,而没有事务环境,它会抛出异常。 4. PROPAGATION_REQUIRES_NEW 无论当前是否已有事务,方法都会创建一个新的事务,并在新的事务中运行。现有事务会被挂起,直到新事务结束。 ```java @...

    spring 注解事务管理

    - `noRollbackFor`: 指定不会导致事务回滚的异常类型,即使方法抛出这些异常,事务也不会回滚。 ### 4. 示例 ```java @Service public class UserService { @Autowired private UserRepository userRepository;...

    Spring Boot的事务控制.docx

    // 手动抛出运行时异常以触发事务回滚 } return null; } @Override @Transactional(rollbackFor = Exception.class) public Long addBook(Book book) { try { Long result = bookRepository.addBook(book)...

Global site tag (gtag.js) - Google Analytics