当前位置: 首页 >服务端 > 关于spring事务注解实战

关于spring事务注解实战

1.概述

spring的事务注解@Transaction 相信很多人都用过,而@Transaction 默认配置适合80%的配置。

本篇文章不是对spring注解事务做详细介绍,而是解决一些实际场景下遇到的问题

spring事务注解的基本原理

关于spring事务注解实战 _ JavaClub全栈架构师技术笔记

下面针对是否需要开启事务和是否需要回滚事务在特定场景下的介绍

2.事务回滚

2.1 默认回滚策略

@Transactionalpublic void rollback() throws SQLException {// update dbthrow new SQLException("exception");}


上述代码事务会回滚吗?不会的,就算抛出SQLException了,但是之前的数据库操作依然会提交,原因就是@Transactional默认情况下只回滚RuntimeException和Error。

2.2 指定回滚异常

因此,如果要指定哪些异常需要回滚,则通过配置@Transactional中rollbackFor,例如

@Transactional(rollbackFor = {SQLException.class})public void rollback() throws SQLException {// update dbthrow new SQLException("exception");}

按照上面例子,那指定的SQLException,当抛出RuntimeException的时候,还会回滚吗?

@Transactional(rollbackFor = {SQLException.class})public void rollback() throws SQLException {// update dbthrow new Runtime("exception");}

还是会回滚的。

2.3 事务嵌套的回滚

假设有下面的逻辑,事务会回滚吗(或者说 updateA,updateB,updateC)哪些更新会提交

@Transactionalpublic void rollback() {// updateAtry{selfProxy.innelTransaction()}catch(RuntimeException e){//do nothing}//updateC} @Transactionalpublic void innelTransaction() throws SQLException {// updateBthrow new RuntimeException("exception");}

 

答案是会回滚,因为内部事务触发回滚,当前事务被标记为 rollback-only,

当外部事务提交的时候,Spring抛出以下异常,同时回滚外部事务

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
 

2.4 小结

所以,在需要事务回滚的时候,最好还是抛出RuntimeException,并且不要在代码中捕获此类异常

三、事务传播性

@Transaction中的propagation的可以配置事务的传播性,网上介绍的很多,就直接复制一段

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 (也是默认策略)PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。 

3.1 如何在事务中读取最新配置

有时候需要在一个事务中,读取最新数据(默认是读取事务开始前的快照)。其实很简单,只要使用上面PROPAGATION_NOT_SUPPORTED传播性就可以了。

@Transactionalpublic void transaction() throws SQLException {// do somethingselfProxy.queryNewValue();} @Transactional(propagation = Propagation.NOT_SUPPORTED)public void queryNewValue() throws SQLException {//查询数据中的最新值} 

 

四、内部调用事务方法

事务注解的实质就是在创建一个动态代理,在调用事务方法前开启事务,在事务方法结束以后决定是事务提交还是回滚。

因此,直接在类内部中调用事务方法,是不会经过动态代理的

关于spring事务注解实战 _ JavaClub全栈架构师技术笔记

 

。 因此,如果要使方法B点事务生效,必须这样 

 关于spring事务注解实战 _ JavaClub全栈架构师技术笔记

 

4.1 解决办法

解决思路:需要在内部调用方法B的时候,找到当前类的代理类,用代理类去调用方法B

4.1.1 解决办法1

 
@Servicepublic class MyService{@Transactionalpublic void transaction(){// do something((MyService) AopContext.currentProxy()).queryNewValue();} @Transactional(propagation = Propagation.NOT_SUPPORTED)public void queryNewValue(){//查询数据中的最新值}}


通过AopContext.currentProxy()可以拿到当前类的代理类,但是要使用这个时候,必须在启动类上加上

@EnableAspectJAutoProxy(exposeProxy=true)

4.1.2 解决办法2

既然是要拿到当前代理类,那其实直接在Spring的容器里面去拿也可以啊。在spring中拿Bean的方法大致有2种

通过注入

@Servicepublic class MyService{@Autowiredprivate MyService self;@Transactionalpublic void transaction() {// do somethingself.queryNewValue();} @Transactional(propagation = Propagation.NOT_SUPPORTED)public void queryNewValue() {//查询数据中的最新值}}

tips:spring现在对一些循环依赖是提供支持的,简单来说,满足:

  1. Bean是单例
  2. 注入的方式不是构造函数注入

通过BeanFactory

 

@Servicepublic class MyService implements BeanFactoryAware{private MyService self; @Transactionalpublic void transaction(){// do somethingself.queryNewValue();} @Transactional(propagation = Propagation.NOT_SUPPORTED)public void queryNewValue() {//查询数据中的最新值}  @Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {self = beanFactory.getBean(MyService.class);}}

 

4.2 需要注意的地方

    • 使用@Transaction注解的方法,必须用public来修饰。
    • 其实不止是@Transaction,其他类似@Cacheable,@Retryable等依赖spring proxy也必须使用上述方式达到内部调用。
    • @Transactional,@Async放在同一个类中,如果使用Autowire注入会循环依赖,而使用BeanFactoryAware会使得@Transactional无效

作者:atheva
来源链接:https://www.cnblogs.com/lizo/p/8534778.html

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。





本文链接:https://www.javaclub.cn/server/112835.html

标签:Spring注解
分享给朋友:

“关于spring事务注解实战” 的相关文章

linux yum命令详解 2022年05月19日 19:54:29
Java日志框架那些事儿 2022年05月19日 20:04:37
关于设计模式 2022年05月23日 23:02:13
windows 安装python环境 2022年06月14日 06:45:11
python安装及环境变量 2022年06月15日 08:23:05
RabbitMQ原理 2022年06月16日 22:16:38