@Transactional详解与使用示例
@Transactional
- @Transactional
- 添加位置
- @Transactional 实现原理
- 事务的隔离级别
- 事务传播行为
- spring事务回滚规则
- 演示示例
@Transactional
package org.springframework.transaction.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;import org.springframework.core.annotation.AliasFor;
import org.springframework.transaction.TransactionDefinition;/*** Describes a transaction attribute on an individual method or on a class.** <p>At the class level, this annotation applies as a default to all methods of* the declaring class and its subclasses. Note that it does not apply to ancestor* classes up the class hierarchy; methods need to be locally redeclared in order* to participate in a subclass-level annotation.** <p>This annotation type is generally directly comparable to Spring's* {@link org.springframework.transaction.interceptor.RuleBasedTransactionAttribute}* class, and in fact {@link AnnotationTransactionAttributeSource} will directly* convert the data to the latter class, so that Spring's transaction support code* does not have to know about annotations. If no rules are relevant to the exception,* it will be treated like* {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute}* (rolling back on {@link RuntimeException} and {@link Error} but not on checked* exceptions).** <p>For specific information about the semantics of this annotation's attributes,* consult the {@link org.springframework.transaction.TransactionDefinition} and* {@link org.springframework.transaction.interceptor.TransactionAttribute} javadocs.** @author Colin Sampaleanu* @author Juergen Hoeller* @author Sam Brannen* @since 1.2* @see org.springframework.transaction.interceptor.TransactionAttribute* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute* @see org.springframework.transaction.interceptor.RuleBasedTransactionAttribute*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {/*** Alias for {@link #transactionManager}.* @see #transactionManager*/@AliasFor("transactionManager")String value() default "";/*** A <em>qualifier</em> value for the specified transaction.* <p>May be used to determine the target transaction manager,* matching the qualifier value (or the bean name) of a specific* {@link org.springframework.transaction.PlatformTransactionManager}* bean definition.* @since 4.2* @see #value*/@AliasFor("value")String transactionManager() default "";/*** The transaction propagation type.* <p>Defaults to {@link Propagation#REQUIRED}.* @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior()*/Propagation propagation() default Propagation.REQUIRED;/*** The transaction isolation level.* <p>Defaults to {@link Isolation#DEFAULT}.* <p>Exclusively designed for use with {@link Propagation#REQUIRED} or* {@link Propagation#REQUIRES_NEW} since it only applies to newly started* transactions. Consider switching the "validateExistingTransactions" flag to* "true" on your transaction manager if you'd like isolation level declarations* to get rejected when participating in an existing transaction with a different* isolation level.* @see org.springframework.transaction.interceptor.TransactionAttribute#getIsolationLevel()* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setValidateExistingTransaction*/Isolation isolation() default Isolation.DEFAULT;/*** The timeout for this transaction (in seconds).* <p>Defaults to the default timeout of the underlying transaction system.* <p>Exclusively designed for use with {@link Propagation#REQUIRED} or* {@link Propagation#REQUIRES_NEW} since it only applies to newly started* transactions.* @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()*/int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;/*** A boolean flag that can be set to {@code true} if the transaction is* effectively read-only, allowing for corresponding optimizations at runtime.* <p>Defaults to {@code false}.* <p>This just serves as a hint for the actual transaction subsystem;* it will <i>not necessarily</i> cause failure of write access attempts.* A transaction manager which cannot interpret the read-only hint will* <i>not</i> throw an exception when asked for a read-only transaction* but rather silently ignore the hint.* @see org.springframework.transaction.interceptor.TransactionAttribute#isReadOnly()* @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly()*/boolean readOnly() default false;/*** Defines zero (0) or more exception {@link Class classes}, which must be* subclasses of {@link Throwable}, indicating which exception types must cause* a transaction rollback.* <p>By default, a transaction will be rolling back on {@link RuntimeException}* and {@link Error} but not on checked exceptions (business exceptions). See* {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)}* for a detailed explanation.* <p>This is the preferred way to construct a rollback rule (in contrast to* {@link #rollbackForClassName}), matching the exception class and its subclasses.* <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class clazz)}.* @see #rollbackForClassName* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)*/Class<? extends Throwable>[] rollbackFor() default {};/*** Defines zero (0) or more exception names (for exceptions which must be a* subclass of {@link Throwable}), indicating which exception types must cause* a transaction rollback.* <p>This can be a substring of a fully qualified class name, with no wildcard* support at present. For example, a value of {@code "ServletException"} would* match {@code javax.servlet.ServletException} and its subclasses.* <p><b>NB:</b> Consider carefully how specific the pattern is and whether* to include package information (which isn't mandatory). For example,* {@code "Exception"} will match nearly anything and will probably hide other* rules. {@code "java.lang.Exception"} would be correct if {@code "Exception"}* were meant to define a rule for all checked exceptions. With more unusual* {@link Exception} names such as {@code "BaseBusinessException"} there is no* need to use a FQN.* <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String exceptionName)}.* @see #rollbackFor* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)*/String[] rollbackForClassName() default {};/*** Defines zero (0) or more exception {@link Class Classes}, which must be* subclasses of {@link Throwable}, indicating which exception types must* <b>not</b> cause a transaction rollback.* <p>This is the preferred way to construct a rollback rule (in contrast* to {@link #noRollbackForClassName}), matching the exception class and* its subclasses.* <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class clazz)}.* @see #noRollbackForClassName* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)*/Class<? extends Throwable>[] noRollbackFor() default {};/*** Defines zero (0) or more exception names (for exceptions which must be a* subclass of {@link Throwable}) indicating which exception types must <b>not</b>* cause a transaction rollback.* <p>See the description of {@link #rollbackForClassName} for further* information on how the specified names are treated.* <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String exceptionName)}.* @see #noRollbackFor* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)*/String[] noRollbackForClassName() default {};}
属性 | 类型 | 描述 |
---|---|---|
value | String | 可选的限定描述符,指定使用的事务管理器 |
transactionManager | String | 可选的限定描述符,指定事务的限定符值 |
propagation | enum:Propagation | 可选的事务传播行为设置 |
isolation | enum:isolation | 可选的事务隔离级别设置 |
timeout | int (in seconds granularity) | 事务超时时间设置 |
readOnly | boolean | 读写或只读事务,默认读写 |
rollbackFor | Class对象数组,必须继承自Throwable | 导致事务回滚的异常类数组 |
rollbackForClassName | 类名数组,必须继承自Throwable | 导致事务回滚的异常类名字数组 |
noRollbackFor | Class对象数组,必须继承自Throwable | 不会导致事务回滚的异常类数组 |
noRollbackForClassName | 类名数组,必须继承自Throwable | 不会导致事务回滚的异常类名字数组 |
添加位置
1)接口实现类或接口实现方法上,而不是接口类中。
2)访问权限:public 的方法才起作用。@Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。
系统设计:将标签放置在需要进行事务管理的方法上,而不是放在所有接口实现类上:只读的接口就不需要事务管理,由于配置了@Transactional就需要AOP拦截及事务的处理,可能影响系统性能。
@Transactional 实现原理
@Transactional 实质是使用了 JDBC 的事务来进行事务控制的
@Transactional 基于 Spring 的动态代理的机制
@Transactional 实现原理:
事务开始时,通过AOP机制,生成一个代理connection对象,
并将其放入 DataSource 实例的某个与 DataSourceTransactionManager 相关的某处容器中。
在接下来的整个事务中,客户代码都应该使用该 connection 连接数据库,
执行所有数据库命令。
[不使用该 connection 连接数据库执行的数据库命令,在本事务回滚的时候得不到回滚]
(物理连接 connection 逻辑上新建一个会话session;
DataSource 与 TransactionManager 配置相同的数据源)事务结束时,回滚在第1步骤中得到的代理 connection 对象上执行的数据库命令,
然后关闭该代理 connection 对象。
(事务结束后,回滚操作不会对已执行完毕的SQL操作命令起作用)
事务的隔离级别
是指若干个并发的事务之间的隔离程度
- @Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读,
不可重复读) 基本不使用- @Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)
- @Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
- @Transactional(isolation = Isolation.SERIALIZABLE):串行化
事务传播行为
如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为
- TransactionDefinition.PROPAGATION_REQUIRED:
如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。- TransactionDefinition.PROPAGATION_REQUIRES_NEW:
创建一个新的事务,如果当前存在事务,则把当前事务挂起。- TransactionDefinition.PROPAGATION_SUPPORTS:
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:
以非事务方式运行,如果当前存在事务,则把当前事务挂起。- TransactionDefinition.PROPAGATION_NEVER:
以非事务方式运行,如果当前存在事务,则抛出异常。- TransactionDefinition.PROPAGATION_MANDATORY:
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。- TransactionDefinition.PROPAGATION_NESTED:
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;
如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
spring事务回滚规则
- 指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常,spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务
- 默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常不会导致事务回滚。
- 用spring事务管理器,由spring来负责数据库的打开、提交、回滚、默认遇到运行期例外(throw new RuntimeException(“注释”))会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new RuntimeException(“注释”))不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚要想所有异常都回滚,要加上@Transactional(rollbackFor={Exception.class,其他异常}),如果让unchecked例外不回滚;@Transactional(notRollbackFor=RunTimeException.class)
演示示例
@Transactional注解支持10个属性的设置,这里只讲解其中使用较多的三个属性:propagation、isolation、rollbackFor 。其中propagation属性用来枚举事务的传播行为,isolation用来设置事务隔离级别,rollbackFor进行异常事务回滚。
模拟银行转账:用户1向用户2转500
准备数据
@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
- 没有使用@Transactional
模拟正常转账
@Service
public class TestUserServiceImpl extends ServiceImpl<TestUserMapper, TestUser> implements TestUserService {@Overridepublic void testUser(TestUser testUser) throws CoBusinessException {// 更新用户1,减500TestUser one = getById(1);one.setMoney(500);updateById(one);// 查询用户2的金额是否超过最大值,是抛异常,否正常通过TestUser two = getById(2);if (two.getMoney() > 1400) {throw new RuntimeException("金额过大");}// 更新用户2的余额two.setMoney(1500);updateById(two);}
}
数据库表的变化
- 变化前
- 变化后
模拟转账异常
public class TestUserServiceImpl extends ServiceImpl<TestUserMapper, TestUser> implements TestUserService {@Overridepublic void testUser(TestUser testUser) throws CoBusinessException {// 更新用户1,减500TestUser one = getById(1);one.setMoney(500);updateById(one);// 查询用户2的金额是否超过最大值,是抛异常,否正常通过TestUser two = getById(2);if (two.getMoney() > 400) {throw new RuntimeException("金额过大");}// 更新用户2的余额two.setMoney(1500);updateById(two);}
}
数据库表的变化
- 变化前
- 变化后
总结:可以看出,没有加@Transactional,在正常情况下是没有问题的,但是出现异常,就会发现,第一条数据已经发生了更改,第二条却没有,这就导致了数据不同步,会很不好。
- 使用了@Transactional
模拟正常转账
@Service
public class TestUserServiceImpl extends ServiceImpl<TestUserMapper, TestUser> implements TestUserService {@Override@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})public void testUser(TestUser testUser) throws CoBusinessException {// 更新用户1,减500TestUser one = getById(1);one.setMoney(500);updateById(one);// 查询用户2的金额是否超过最大值,是抛异常,否正常通过TestUser two = getById(2);if (two.getMoney() > 1400) {throw new RuntimeException("金额过大");}// 更新用户2的余额two.setMoney(1500);updateById(two);}
}
数据库表的变化
- 变化前
- 变化后
模拟转账异常
public class TestUserServiceImpl extends ServiceImpl<TestUserMapper, TestUser> implements TestUserService {@Override@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})public void testUser(TestUser testUser) throws CoBusinessException {// 更新用户1,减500TestUser one = getById(1);one.setMoney(500);updateById(one);// 查询用户2的金额是否超过最大值,是抛异常,否正常通过TestUser two = getById(2);if (two.getMoney() > 400) {throw new RuntimeException("金额过大");}// 更新用户2的余额two.setMoney(1500);updateById(two);}
}
数据库表的变化
- 变化前
- 变化后
总结:可以看出,加上了@Transactional,不管是正常情况,还是异常情况,都不会出现两边数据有异常
@Transactional详解与使用示例相关推荐
- @Transactional 详解 示例
@Transactional 是声明式事务管理 编程中使用的注解 参考 @Transactional 详解 Spring之@Transactional注解原理以及走过的坑 Spring事务的原理 Sp ...
- python字典的用法_Python字典的用法详解(附示例)
本篇文章给大家带来的内容是关于Python字典的用法详解(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 字典的表现形式为:{key:value},键和值之间用冒号分隔,每个 ...
- java集合框架的结构_集合框架(Collections Framework)详解及代码示例
简介 集合和数组的区别: 数组存储基础数据类型,且每一个数组都只能存储一种数据类型的数据,空间不可变. 集合存储对象,一个集合中可以存储多种类型的对象.空间可变. 严格地说,集合是存储对象的引用,每个 ...
- java学习 类变量 类方法_这篇文章主要介绍了JAVA类变量及类方法代码实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下类变量(...
这篇文章主要介绍了JAVA类变量及类方法代码实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 类变量(static) 类变量是该类的所有对象共 ...
- Freesurfer recon-all命令详解及使用示例
Freesurfer recon-all命令详解及使用示例 一.一些名词解释 atlas 模板,带标签的地图 CA Canonical 典型的,规范的(CA Normalize, CA Registe ...
- 用计算机函数查找,Excel查找函数Vlookup详解及应用示例-excel技巧-电脑技巧收藏家...
Excel查找函数Vlookup详解及应用示例 招如其名.此招用来在一个茫茫的数据源中,自动让电脑找出你要的某个数据的相关资料并填在指定的地方.也是就是,可以让电脑在一个表格或指定的一个区域中查找某一 ...
- 三维空间刚体运动1:旋转矩阵与变换矩阵(详解加代码示例)
三维空间刚体运动1:旋转矩阵与变换矩阵(详解加代码示例) 1. 点.向量和坐标系 2.坐标系间的欧式变换 2.1 旋转 2.2 平移 3.齐次坐标和变换矩阵 4. 相似.仿射和射影变换 4.1 相似变 ...
- 如何使用计算机Excel公式if,Excel条件函数If详解及应用示例-excel技巧-电脑技巧收藏家...
Excel条件函数If详解及应用示例 此招用来对某一条件执行的真假值进行判断,根据逻辑计算的真假值,返回不同结果.如果结果为真,则返回一个真,如果为假,则返回另一值,可谓左右逢源. 使用语法 IF(l ...
- Python线性规划库Pulp的详解及应用示例
Python线性规划库Pulp的详解及应用示例 线性规划是一种常见的优化方法,在商业.工程等领域有着广泛的应用.而Python作为一种高效.灵活的编程语言,也提供了丰富的线性规划库可供选择.本文将介绍 ...
最新文章
- urlencode和quote的用法
- 反弹和补遗:再论Bjarne Stroustrup的基于对象的含义
- 连续2年入不敷出,青云流血冲刺科创板:拟募资11.88亿,最近三年净亏4.37亿
- FileLocatorPro正则表达式批量搜索文件中的字符串
- Java8-5-Function函数式接口进阶与默认方法详解
- 漫画:程序员一时单身一时爽,一直单身...有点惨
- [Unity3d]u3d中定时器的使用
- JAVA中string的赋值_Java中关于String赋值的两种形式
- MAC OS 10.12 安装任意来源应用
- g++ -std=c++_在C ++ std库中使用sort()
- DBeaverEE for Mac(数据库管理工具)
- 2021 OpenCV人工智能竞赛优秀项目团队介绍集锦(六)
- 来到广西的十年之吃喝
- 电脑和ubuntu开发板用网线连接的方法
- 微信支付:appid 与 openId 不配
- 项目二--03.基于Nginx、keepalived的高可用集群之keepalived高可用实现
- 数学与计算机科学虎扑,数学发展到今天还有继续研究的必要吗?
- python百度识别花草_用python代码实现调用百度的免费植物识别接口
- Keil(C51)安装与注册
- 【pyqt】自制的图片裁剪分割器