Spring中@Transactional事务回滚

一、Spring 默认事务

Spring中 @Transactional 注解,默认情况下,只对抛出的 RuntimeException 异常,才会事务回滚。

  • 如果事务的方法中抛出 unchecked异常(RuntimeException),事务会进行回滚( rollback);
  • 如果事务的方法中抛出是 checked异常(Exception),事务不会回滚。

也就是说,默认情况下, @Transactional 注解 只对抛出的 RuntimeException 异常和其子类异常 才有效,对 Exception 及 Exception 的子类异常无效。

伪代码说明

// @Transactional 默认就是 RuntimeException 有效,抛出 RuntimeException时,事务会回滚。
@Transactional     
public void methodName1() {
	//... 各种的业务逻辑省略	
	throw new RuntimeException("RuntimeException");	
}

// @Transactional 默认就是 RuntimeException 有效,抛出 Exception 时,事务不会回滚。
@Transactional
public void methodName22() {
	//... 各种的业务逻辑省略
	throw new Exception("Exception");
}

// @Transactional 指定回滚事务是 Exception时,遇到 RuntimeException 时,事务不会回滚
@Transactional( rollbackFor=Exception.class )
public  void methodName3() {
	//... 各种的业务逻辑省略
	throw new RuntimeException("RuntimeException");
}

// @Transactional 指定回滚事务是 Exception时,遇到异常 Exception 时,事务会回滚,
@Transactional( rollbackFor=Exception.class ) 
public void methodName4() {
	//... 各种的业务逻辑省略
	throw new Exception("Exception");
}

@Transactional 相当于 @Transactional(rollbackFor=RuntimeException.class) ,只对抛出的 RuntimeException 异常,才会事务回滚。

1.1、抛出 unchecked 和 checked 异常都回滚

如果希望无论抛出是 RuntimeException (unchecked ) ,还是 Exception (checked),事务都要回滚。

@Transactional( rollbackFor = {RuntimeException.class, Exception.class} )
public  void methodName5() {
	//... 业务省略
	if(){		
		throw new RuntimeException("RuntimeException");
	}
	
	//... 业务省略
	if(){		
		throw new Exception("Exception");
	}	
}

1.2、总结

  • Spring 中 @Transactional ,默认只对抛出的 RuntimeException 的出常,事务才会回滚。

  • 如果希望无论抛出是 RuntimeException ,还是 Exception,事务都要回滚,请使用如下配置。

    @Transactional(rollbackFor={RuntimeException.class, Exception.class})
    

二、使用 Spring中 @Transactional 注解的注意事项

  1. @Transactional 注解只能应用到 public 的方法上。
    如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。

  2. 配置 proxy-target-class 是指定基于接口的,还是基于类的代理被创建。

    如果 proxy-target-class = false (默认值),那么标准的JDK基于接口的代理。
    如果 proxy-target-class = true,那么基于类的代理将起作用(需要CGLIB库)。

  3. @Transactional 注解 加在 具体方法(或类)上面 ,而不是接口上面。
    在接口上使用 @Transactional 注解,只能当你设置了基于接口的代理时它才生效。
    因为注解是 不能继承 的,这就意味着如果正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装。

  4. @Transactional 的事务是通过基于接口的,或者是基于类的代理才能被创建。在同一个类中一个方法调用另一个有事务注解的方法,事务是不会起作用的。

    这条能理解吗 ?下面是解释说明。

    伪代码说明

    @Serive
    public class XxxService{	
    	
    	public void aa(){
    		//业务...
    		bb()
    		//业务...
    	}
    	
    	@Transactional
    	public void bb(){
    		//业务...
    	}
    }
    
    @Controller
    public class XxxController(){
    	
    	@Autowired
    	XxxService xxxService;
    	
    	@RquestMapping("/hello")
    	public void hello(){
    		xxxService.aa();
    	}
    }
    
    XxxController.hello() 调用 XxxService 时,没有开启事务,在 aa()bb()发生的RuntimerException 不会事务回滚。
    
    分析说明:
    (1)因为 aa() 没有 @Transactional 注解,因此 XxxController 调用 XxxService 时 ,没有开启事务;
    (2aa()中调有 bb() 只是方法的调用(代码片段的调用)。类似于Thread中,开启线程是通过start()方法,而不是直接调用run()方法。
    

    spring 在扫描bean的时候会扫描方法上是否包含@Transactional 事务注解,如果包含,则 spring会为这个bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个bean 。

    当这个有事务注解的方法被调用的时候,实际上是由代理类来调用的,代理类在调用之前就会开启事务(transaction) 。

    但是,如果先调用一个没有事务的方法,然通这个方法再去有事务,由于该方法的调用并没有通过代理类,而是直接通过原来的那个bean,所以就不会启动transaction,我们看到的现象就是 @Transactional 注解无效。

    总结:
    同一个类中,一个没有事务的方法A,去调用另一个有事务的方法B时,因为是直接调用,而不是调用的代理类,所以事务不起用的。

  • 8
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
Spring框架,使用 @Transactional 注解可以控制事务的行为。其,事务的回滚可以通过设置 @Transactional 注解的 rollbackFor 或 noRollbackFor 属性来实现。rollbackFor 属性用于指定哪些异常触发事务回滚,而 noRollbackFor 属性用于指定哪些异常不触发事务回滚。这样,在方法执行过程,如果抛出了设置的异常类型,事务将会回滚。另外,@Transactional 注解还支持在方法上使用 rollbackOnly 属性来强制回滚事务。 需要注意的是,如果一个没有事务的方法调用了一个有事务的方法,由于调用没有经过代理类,而是直接调用原始的 Bean,那么 @Transactional 注解将会失效,事务将无法回滚。因此,在使用 @Transactional 注解时,要注意方法之间的调用关系,确保事务能够正确地被应用和回滚。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Spring 事务 -- @Transactional的使用](https://blog.csdn.net/wl1101780628/article/details/110120587)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Spring@Transactional事务回滚](https://blog.csdn.net/xiaojin21cen/article/details/83507174)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值