CreateArtTechnology
/ Blog
Login
最新文章
Java
语言相关
库相关
虚拟机相关
CreateArtTechnology
项目搭建
使用的工具
自研的工具
开源工具
ELK
ElasticSearch
Jenkins
Markdown
GraphQL
Arthas
生产工具
Linux
Nginx
VersionControl
Subversion
Git
Redis
Archiva
Maven
Zookeeper
Spring
SpringBoot
MySql
HBase
Cassandra
容器化
Docker
Kubernetes
服务容器化从零开始
未分类笔记
算法相关
概念相关
豆知识
机器学习
机器学习从零开始
Spring事务的配置与使用
13
2019-04-24 18:56:56
生产工具
Spring
## Spring支持的事务 Spring提供两种事务管理方式,分为编程式和声明式。 - `编程式`:通过编码的方式手动启用、提交或回滚事务,粒度更细,但更麻烦。 - `声明式`:通过在方法或类或接口上添加注解进行包装,无侵入地实现事务,更方便,但粒度更大。 需要注意的是,使用的数据库需要支持事务,否则事务将不起作用。如MySql的MyIsam引擎就不支持事务。 ## Spring事务的配置 **添加依赖** ```xml
org.springframework
spring-tx
${spring.version}
``` **配置事务管理器** ```xml
``` 显然,transactionManager的dataSource应该是代码中进行事务操作的dataSource,不然怎么管理呢。 ### 编程式事务的使用 在代码中开始、提交或回滚事务: ```java // 开始事务 TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition()); // 异常回滚,并不一定要在try...catch中 transactionManager.rollback(status); // 提交事务 transactionManager.commit(status); ``` 通常比较合适的使用方法: ```java TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition()); try { // 进行需要处在同一事务中的数据库操作 ...... // 正常结束,提交事务 transactionManager.commit(status); } catch (SomeException) { // 错误处理 ...... // 回滚 transactionManager.rollback(status); } ``` ### 声明式事务的使用 直接在类或在方法上添加`@Transaction`注解即可: ```java @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class) public int save(Info info) throws Exception { ``` `@Transaction`注解的常用参数: **propagation 传播行为** - `REQUIRED(默认值)` 必须在一个具有事务的上下文中运行:如果当前没有(外层)事务,就新建一个事务;如果当前存在(外层)事务,则加入到当前(外层)事务中。(如果被调用方法发生异常,那么调用方法和被调用方法的事务都将回滚)这是最常用的选择。 - `SUPPORTS` 支持当前(外层)事务,如果当前没有(外层)事务,就以非事务方式执行。 - `MANDATORY` 强制使用当前(外层)事务,如果当前没有(外层)事务,就抛出异常。 - `REQUIRES_NEW` 新建一个事务,并在该事务中运行,如果当前存在(外层)事务,则先将当前(外层)事务挂起 - `NOT_SUPPORTED` 以非事务方式执行操作:如果当前存在(外层)事务,就把当前(外层)事务挂起。 - `NEVER` 以非事务方式执行:如果当前存在(外层)事务,则抛出异常。 - `NESTED` 以嵌套方式执行:如果当前存在(外层)事务,则以嵌套方式独立运行于自己的事务中,不影响当前(外层)事务,而当前(外层)事务如果回滚,则该事务也必须回滚;如果当前不存在(外层)事务,则执行与PROPAGATION.REQUIRED类似的操作。 **isolation 隔离级别** - `DEFAULT` 使用数据库默认的事务隔离级别 - `READ_UNCOMMITTED` 允许读取尚未提交的修改,可能导致脏读、幻读和不可重复读 - `READ_COMMITTED` 允许从已经提交的事务读取,可防止脏读,但幻读、不可重复读仍然有可能发生 - `REPEATABLE_READ` 对相同字段的多次读取的结果是一致的,除非数据被当前事务自身修改。可防止脏读和不可重复读,但幻读仍有可能发生 - `SERIALIZABLE` 完全服从ACID隔离原则,确保不发生脏读、不可重复读、和幻读,但执行效率最低。 **readOnly 是否只读事务** 表示该事务是否只读取数据但不更新数据,只有读取操作的事务设置为只读可以帮助数据库引擎优化事务。 **timeout 超时时间** 避免对数据库长时间锁定,单位秒。 **rollbackFor 回滚异常类** 默认只对运行时异常进行回滚,参见下文。 ## 声明式事务的缺陷 ### 类内部调用 Spring的声明式事务是通过AOP的方式动态代理的,因此会产生一个实现了事务代理类,区分于原始类。考虑一种情况: - Service类中的方法A没有声明事务 - Service中的方法B声明了事务 - 方法A内部调用方法B 此时,调用Service的方法B,使用的是代理类Service'的方法B,是实现了事务方法的,出现异常会回滚。 但如果调用的是方法A,在代理类的内部使用的是原始类Service的方法B,没有实现事务,会导致无法异常回滚。 **解决方法**:将B方法拆分到其他类中并使用事务包裹,保证调用的是代理类而非原始类的方法。 ### 错误的使用方式 声明式事务包装的方法在方法抛出异常时会回滚,但是默认只在抛出`RuntimeException`时回滚。 如果异常被catch住吞掉了,或是抛出了非`RuntimeException`,那么默认是不回滚的。 **解决方法**:不要吞异常,遇到非`RuntimeException`,使用`@Transaction`注解的`rollbackFor`参数进行控制。 Java8中java.lang的部分类分层结构如下(完整结构请查看文章底部参考资料): ```txt java.lang.Object ...... java.lang.Throwable (implements java.io.Serializable) java.lang.Error java.lang.AssertionError java.lang.LinkageError java.lang.BootstrapMethodError java.lang.ClassCircularityError java.lang.ClassFormatError java.lang.UnsupportedClassVersionError java.lang.ExceptionInInitializerError java.lang.IncompatibleClassChangeError java.lang.AbstractMethodError java.lang.IllegalAccessError java.lang.InstantiationError java.lang.NoSuchFieldError java.lang.NoSuchMethodError java.lang.NoClassDefFoundError java.lang.UnsatisfiedLinkError java.lang.VerifyError java.lang.ThreadDeath java.lang.VirtualMachineError java.lang.InternalError java.lang.OutOfMemoryError java.lang.StackOverflowError java.lang.UnknownError java.lang.Exception java.lang.CloneNotSupportedException java.lang.InterruptedException java.lang.ReflectiveOperationException java.lang.ClassNotFoundException java.lang.IllegalAccessException java.lang.InstantiationException java.lang.NoSuchFieldException java.lang.NoSuchMethodException // 这里是RuntimeException java.lang.RuntimeException java.lang.ArithmeticException java.lang.ArrayStoreException java.lang.ClassCastException java.lang.EnumConstantNotPresentException java.lang.IllegalArgumentException java.lang.IllegalThreadStateException java.lang.NumberFormatException java.lang.IllegalMonitorStateException java.lang.IllegalStateException java.lang.IndexOutOfBoundsException java.lang.ArrayIndexOutOfBoundsException java.lang.StringIndexOutOfBoundsException java.lang.NegativeArraySizeException java.lang.NullPointerException java.lang.SecurityException java.lang.TypeNotPresentException java.lang.UnsupportedOperationException ...... ``` ## 参考资料 [Spring声明式事务 - 简书](https://www.jianshu.com/p/3ee512fd419e) [spring声明式事务 同一类内方法调用事务失效-云栖社区-阿里云 (ps. 这不是原文,我实在找不着原文了)](https://yq.aliyun.com/articles/269375/) [java.lang Class Hierarchy (Java Platform SE 8 )](https://docs.oracle.com/javase/8/docs/api/java/lang/package-tree.html)
发布文章 101
文章被阅读 1820
最近修改
什么是“丝滑”的曲线
2021-12-08 15:19:20
高效空间数据索引R树及其批量加载方法STR简介
2021-09-29 20:33:37
关于分库分表的一些事儿
2021-06-25 11:51:25
获得诺奖的稳定匹配理论之TTC算法与GS算法
2021-03-14 23:04:48
算法小白的机器学习入门实践,从零到上线
2021-01-13 14:28:27
分站宗旨
一站式资料平台,减少重复检索,减少重复采坑。