Spring中@Transactional事务回滚
Posted 猎人在吃肉
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring中@Transactional事务回滚相关的知识,希望对你有一定的参考价值。
一、Spring 默认事务
Spring中 @Transactional
注解,默认情况下只对 RuntimeException
异常进行事务的回滚。
- 如果事务的方法中抛出 unchecked异常(RuntimeException),事务会进行回滚( rollback);
- 如果事务的方法中抛出是 checked异常(Exception),事务不会回滚。
也就是说,默认情况下, @Transactional
注解 只对抛出的 RuntimeException
异常有效,对 Exception 及 Exception 的子类异常无效。
伪代码示例说明
// @Transactional 默认就是RuntimeException有效,抛出Exception时,事务不会回滚。
@Transactional
public void methodName1()
//... 各种的业务逻辑省略
throw new Exception("Exception");
//@Transactional 默认就是RuntimeException有效,抛出RuntimeException时,事务会回滚。
@Transactional
public void methodName2()
//... 各种的业务逻辑省略
throw new RuntimeException("RuntimeException");
//@Transactional 指定回滚事务是 Exception时,遇到异常 Exception 时,事务会回滚,
@Transactional(rollbackFor=Exception.class)
public void methodName3()
//... 各种的业务逻辑省略
throw new Exception("Exception");
//@Transactional 指定回滚事务是 Exception时,遇到 RuntimeException 时,事务不会回滚
@Transactional(noRollbackFor=Exception.class)
public void methodName4()
//... 各种的业务逻辑省略
throw new RuntimeException("RuntimeException");
//指定回滚事务是 RuntimeException 和 Exception 时,无论抛出是 RuntimeException 和 Exception,事务都会回滚
@Transactional(rollbackFor=RuntimeException.class, Exception.class)
public void methodName5()
//... 各种的业务逻辑省略
throw new RuntimeException("RuntimeException");
//... 各种的业务逻辑省略
throw new Exception("Exception");
总结
-
Spring 中
@Transactional
默认抛RuntimeException
异常事务才会回滚。 -
如果希望无论抛出是 RuntimeException ,还是 Exception,事务都要回滚,请使用如下配置。
@Transactional(rollbackFor=RuntimeException.class, Exception.class)
二、使用 Spring中 @Transactional 注解的注意事项
-
在需要事务管理的地方加
@Transactional
注解。@Transactional
注解可以被应用于接口定义、接口方法、类定义和类的 public 方法上。 -
@Transactional
注解只能应用到public
的方法上。
如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。 -
注意仅仅
@Transactional
注解的出现不足于开启事务行为,它仅仅 是一种元数据。必须在配置文件中使用配置元素,才真正开启了事务行为。 -
通过元素的
proxy-target-class
属性值来控制是基于接口的还是基于类的代理被创建。如果
proxy-target-class
属值被设置为false
或者这个属性被省略,那么标准的JDK基于接口的代理将起作用。
如果proxy-target-class
属值被设置为true
,那么基于类的代理将起作用(这时需要CGLIB库)。 -
@Transactional
注解 加在 具体类(或方法)上 ,而不是接口上。
在接口上使用 @Transactional 注解,只能当你设置了基于接口的代理时它才生效。
因为注解是 不能继承 的,这就意味着如果正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装。 -
@Transactional
的事务开启,或者是基于接口的,或者是基于类的代理被创建,所以,在同一个类中一个方法调用另一个方法有事务的方法,事务是不会起作用的。第6条能理解吗 ?下面是解释说明。
spring 在扫描bean的时候会扫描方法上是否包含
@Transactional
事务注解,如果包含,则 spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean 。当这个有事务注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用之前就会开启事务(
transaction
) 。但是,如果先调用一个没有事务的方法,然通这个方法再去有事务,由于该方法的调用并没有通过代理类,而是直接通过原来的那个bean,所以就不会启动transaction,我们看到的现象就是
@Transactional
注解无效。总结:
同一个类中,一个没有事务的方法A,去调用另一个有事务的方法B时,因为是直接调用,而不是调用的代理类,所以事务不起用的。
以上是关于Spring中@Transactional事务回滚的主要内容,如果未能解决你的问题,请参考以下文章
Spring中@Transactional事务回滚(含实例详细讲解,附源码)
spring的@Transactional(rollbackFor=Exception.class)的使用