文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

关于Spring中@Transactional事务回滚的注意事项

2023-05-19 17:12

关注

一、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、总结

@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 时 ,没有开启事务;
(2)aa()中调有 bb() 只是方法的调用(代码片段的调用)。类似于Thread中,开启线程是通过start()方法,而不是直接调用run()方法。

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

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

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

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

到此这篇关于关于Spring中@Transactional事务回滚的注意事项的文章就介绍到这了,更多相关Spring中@Transactional事务回滚内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯