@Transactional和Propagation的使用
@Transactional事务几点注意
这里面有几点需要大家留意:
A. 一个功能是否要事务,必须纳入设计、编码考虑。不能仅仅完成了基本功能就ok。
B. 如果加了事务,必须做好开发环境测试(测试环境也尽量触发异常、测试回滚),确保事务生效。
C. 以下列了事务使用过程的注意事项,请大家留意
- 不要在接口上声明@Transactional ,而要在具体类的方法上使用 @Transactional 注解,否则注解可能无效。
- 不要图省事,将@Transactional放置在类级的声明中,放在类声明,会使得所有方法都有事务。故@Transactional应该放在方法级别,不需要使用事务的方法,就不要放置事务,比如查询方法。否则对性能是有影响的。
- 使用了@Transactional的方法,对同一个类里面的方法调用, @Transactional无效。比如有一个类Test,它的一个方法A,A再调用Test本类的方法B(不管B是否public还是private),但A没有声明注解事务,而B有。则外部调用A之后,B的事务是不会起作用的。(经常在这里出错)
- 使用了@Transactional的方法,只能是public,@Transactional注解的方法都是被外部其他类调用才有效,故只能是public。道理和上面的有关联。故在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错,但事务无效
- 经过在ICORE-CLAIM中测试,效果如下:
- 抛出受查异常XXXException,事务会回滚。
- 抛出运行时异常NullPointerException,事务会回滚。
- Quartz中,execute直接调用加了@Transactional方法,可以回滚;间接调用,不会回滚。(即上文3点提到的)
- 异步任务中,execute直接调用加了@Transactional方法,可以回滚;间接调用,不会回滚。(即上文3点提到的)
- 在action中加上@Transactional,不会回滚。切记不要在action中加上事务。
- 在service中加上@Transactional,如果是action直接调该方法,会回滚,如果是间接调,不会回滚。(即上文3提到的)
G.在service中的private加上@Transactional,事务不会回滚。
其属性Propagation的使用:
Spring Transaction中有一个很重要的属性:Propagation。主要用来配置当前需要执行的方法,与当前是否有transaction之间的关系。
我晓得有点儿抽象,这也是为什么我想要写这篇博客的原因。看了后面的例子,大家应该就明白了。
一、Propagation取值:
REQUIRED(默认值):在有transaction状态下执行;如当前没有transaction,则创建新的transaction;
SUPPORTS:如当前有transaction,则在transaction状态下执行;如果当前没有transaction,在无transaction状态下执行;
MANDATORY:必须在有transaction状态下执行,如果当前没有transaction,则抛出异常IllegalTransactionStateException;
REQUIRES_NEW:创建新的transaction并执行;如果当前已有transaction,则将当前transaction挂起;
NOT_SUPPORTED:在无transaction状态下执行;如果当前已有transaction,则将当前transaction挂起;
NEVER:在无transaction状态下执行;如果当前已有transaction,则抛出异常IllegalTransactionStateException。
二、REQUIRED与REQUIRED_NEW
上面描述的6种propagation属性配置中,最难以理解,并且容易在transaction设计时出现问题的是REQUIRED和REQURED_NEW这两者的区别。当程序在某些情况下抛出异常时,如果对于这两者不够了解,就可能很难发现而且解决问题。
下面我们给出三个场景进行分析:
场景一:
ServiceA.java:
public class ServiceA {@Transactionalpublic void callB() {serviceB.doSomething();}
}
ServiceB.java
public class ServiceB {@Transactionalpublic void doSomething() {throw new RuntimeException("B throw exception");}
}
这种情况下,我们只需要在调用ServiceA.callB时捕获ServiceB中抛出的运行时异常,则transaction就会正常的rollback
场景二
在保持场景一中ServiceB不变,在ServiceA中调用ServiceB的doSomething时去捕获这个异常,如下:
public class ServiceA {@Transactionalpublic void callB() {try {serviceB.doSomething();} catch (RuntimeException e) {System.err.println(e.getMessage());}}
}
这个时候,我们再调用ServiceA的callB。程序会抛出org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only这样一个异常信息。原因是什么呢?
因为在ServiceA和ServiceB中的@Transactional propagation都采用的默认值:REQUREID。根据我们前面讲过的REQUIRED特性,当ServiceA调用ServiceB的时候,他们是处于同一个transaction中。如下图所示:
当ServiceB中抛出了一个异常以后,ServiceB会把当前的transaction标记为需要rollback。但是ServiceA中捕获了这个异常,并进行了处理,认为当前transaction应该正常commit。此时就出现了前后不一致,也就是因为这样,抛出了前面的UnexpectedRollbackException。
场景三
在保持场景二中ServiceA不变,修改ServiceB中方法的propagation配置为REQUIRES_NEW,如下:
public class ServiceB {@Transactional(propagation = Propagation.REQUIRES_NEW)public void doSomething() {throw new RuntimeException("B throw exception");}
}
此时,程序可以正常的退出了,也没有抛出UnexpectedRollbackException。原因是因为当ServiceA调用ServiceB时,serviceB的doSomething是在一个新的transaction中执行的。如下图所示:
所以,当doSomething抛出异常以后,仅仅是把新创建的transaction rollback了,而不会影响到ServiceA的transaction。ServiceA就可以正常的进行commit。
当然这里把ServiceA和ServiceB放在两个独立的transaction是否成立,还需要再多多考虑你的业务需求。
@Transactional和Propagation的使用相关推荐
- Spring Boot 中使用 @Transactional 注解配置事务管理
From: https://blog.csdn.net/nextyu/article/details/78669997 事务管理是应用系统开发中必不可少的一部分.Spring 为事务管理提供了丰富的功 ...
- @Transactional之Spring事务深入理解
Spring支持两种事务方式: 编程式事务:使用的是TransactionTemplate(或者org.springframework.transaction.PlatformTransac ...
- @Transactional 使用说明
一.说明 @Tranasctional注解是Spring 框架提供的声明式注解事务解决方案,我们在开发中使用事务保证方法对数据库操作的原子性,要么全部成功,要么全部失败,在使用@Transaction ...
- @Transactional子事务单独提交
需求是在添加了事务的service方法内,执行一个单独事务的添加方法,service报错等导致数据回滚时,单独事务的方法不回滚. 单独提交方法需要放在不用的服务类里,使用Transactional的p ...
- @Transactional详解及其实现步骤
转载至 刘万振 @Transactional 注解管理事务的实现步骤 使用@Transactional 注解管理事务的实现步骤分为两步.第一步,在 xml 配置文件中添加如清单 1 的事务配置信息.除 ...
- Spring事务注解Transactional失效
前情提要:当Service接口实现类中存在内部方法调用,并且方法需要支持事务控制时,事务控制失效,事务的传播级别为默认REQUIRED(默认模式). 1.简化版翻车代码: Service接口层 Ser ...
- spring transactional
事务的实现原理 事务的实现原理.如果说你加了一个 @Transactional 注解,此时 Spring 会使用 AOP 思想,对你的这个方法在执行之前,先去开启一个事务.执行完毕之后,根据你的方法是 ...
- @Transactional
一.作用于接口.接口方法.类以及类方法上 1️⃣当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性. 2️⃣当作用在方法级别时会覆盖类级别的定义. 3️⃣当作用在接口和接口方法时则 ...
- hibernate3
hibernate3 (整合到spring中的core核心配置中的hibernate3) <!-- 基于hibernate的Session工厂 --><bean id="s ...
最新文章
- GlideApp 引入不了问题
- LinearAlgebra_1
- 实战并发编程 - 06线程在执行过程中的状态是如何流转的
- c++ 和 C语言 中数组语法的比较
- IDEA 2020 本土化,真的是全中文了,新手,开心了!
- Winform中实现点击按钮弹窗输入密码验证通过后执行相应逻辑
- 一键清除Delphi中无用的文件
- sklearn朴素贝叶斯分类器_朴素贝叶斯原理
- 【鬼网络】之PXE高效批量网络装机
- python有没有三元运算符_Python基础入门:从变量到异常处理(1)
- 图解elasticsearch原理转载自
- Creating Options Pages
- Java题目:一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?
- Axure RP从入门到精通(一)原型设计工具简介
- 程序员5种编程入门方法,如何快速学会一门编程语言?
- 广义线性模型(GLM)初级教程
- TCR历史研究夏校申请详解
- tensor之维度转换
- 快速识别无效数据(数据有效性/数据验证)
- 2019江西(南昌)安博会 数字冰雹“警视”即将惊艳亮相