目录
一、Spring中事务的实现
1、手动式事务(编程式事务)
Spring操作事务和MySQL操作事务类似,有三个重要步骤:
- 开启事务(获取事务)
- 提交事务
- 回滚事务
使用DataSourceTransactionManager(事务管理器)来开启事务、提交或回滚事务,TransactionDefinition(事务定义)调用相关的api进行事务的操作。
2、声明式事务
Spring声明式事务:添加@Transcational注解。无需手动开启事务和提交事务,进入方法式自动开启事务,执行完后自动提交事务,如果抛出异常会自动回滚事务。
@Transactional工作原理:基于AOP实现。在spring框架启动时,查找bean对象中使用@Transactional注解的方法,进行增强生成代理类,生成的代理类,类似编程式事务。
SpringBoot中使用:
(1)使用SpringBoot对数据库操作的依赖包,其中包含对事务的处理
(2)添加注解,允许SpringBoot框架开启事务统一管理(以@Enable开头的注解,都是允许自动执行的注解)
(3)使用事务,方法添加@Transcational注解
二、事务隔离级别
事务四大特性(ACID):
- 原子性(Atomicity):一个事务中的操作,要么全部执行,要么全部不执行。执行过程中发生错误,会回滚到事务开始前的状态。
- 一致性(Consistency):事务开始之前和结束之后数据库的完整性没有被破坏。
- 持久性(Isolation):事务处理结束后,对数据的修改时永久的。
- 隔离性(Durability):数据库允许多个并发事务同时对其进行读写和修改的操作,隔离性可以防止多个事务并发执行时由于交叉执行而导致的数据不一致。四个隔离级别:读未提交、读提交、可重复读、串行化。
1、MySQL事务隔离级别
四个隔离级别:
- 未提交读(READ UNCOMMITTED):该级别的事务可以看到其他事务中未提交的数据,而未提交的数据可能会发生回滚,因此这个级别读取到的数据为脏数据,称之为脏读;
- 提交读(READ COMMITTED):该级别的事务可以读取到已经提交的事务的数据,不会有脏读问题。但由于在事务的执行过程中可以读取到其它事务提交的结果,所以不同时间的相同SQL查询中,可能得到不同的结果,称为不可重复读。
- 可重复读(REPEATABLE READ):时mysql事务默认的隔离级别,可以确保同一事务多次查询的结果一致。如果次事务正在执行时,另一个事务成功插入某个数据,会导致该事务查询不到这条数据,自己重复插入时会失败,称为幻读。
- 串行化(SERIALZABLE):事务最高隔离级别,会强制事务排序,使之不发生冲突,从而解决曾都、不可重复读、幻读问题。执行效率很低,使用场景不多。
2、Spring事务隔离级别
Spring中事务隔离级别包含五种:
- Isolation.DEFAULT:默认隔离级别,连接的数据库的默认隔离级别。mysql为可重复读,oracle为提交读。
- Isolation.READ_UNCOMMITTED:读未提交
- Isolation.READ_COMMITTED:读已提交
- Isolation.REPEATABLE_READ:可重复读
- Isolation.SERIALIZABLE:串行化
Spring设置事务隔离级别,设置@Transactional中的isolation属性:
@Transactional(isolation = Isolation.SERIALIZABLE)
public Object save(User user) {
// 业务实现
}
三、Spring事务传播机制
Spring事务传播机制定义了多个包含了事务的方法,相互调用时,事务是如何子这些方法之间进行传播的。事务隔离级别保证多个并发事务执行的可控性,而事务传播机制保证一个事务在多个调用方法间是可控的。
通过设置@Transactional注解中的参数propagation。
Spring书屋传播机制包含七种,分为三大类:
(1)支持当前事务
- REQUIRED(需要有):默认的事务传播级别。如果当前存在事务,则加入该事务;如果不存在,则新建一个事务;
- SUPPOSRTS(可以有):如果当前存在事务,则加入该事务;如果当前没有事务,以非事务方式运行;
- MANDATOPY(强制有):如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常;
(2)不支持当前事务
- REQUIRES_NEW:新建事务执行,如果当前存在事务,把当前事务挂起。修饰的内部方法会新开辟自己的事务,且开启的事务相互独立,互不干扰;
- NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,则把当前事务挂起;
- NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常;
(3)NESTED(嵌套事务):如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,等价于REQUIRED。