SpringBoot(二) 事务

2020-08-15 21:37发布

事务处理

Spring Boot事务机制实质上就是Spring的事务处理机制。

1 事务的4大特性

原子性(Atomicity)

一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作。

一致性(Consistency)

一旦事务完成(不管成功还是失败),系统必须确保涉及的数据处于一致的状态,而不会是部分完成部分失败。数据不应该被破坏。

隔离性(Isolation)

并发环境下,一个事务的执行不能不被其他事务干扰。不同的事务并发操作相同的数据时,每个事务都有各自完成的数据空间。

即一个事务内部的操作及使用的数据对其他并发事务时隔离的,并发执行的各个事务之间不能相互干扰。

持久性(Durability)

一旦事务提交,那么它对数据库中的对应数据的状态的变更就会永久保存到数据库中。

2 事务的传播机制

事务的传播性一般用在事务嵌套的场景,比如一个事务方法里面调用了另外一个事务方法。

那么两个方法是各自作为独立的方法提交还是内层的事务合并到外层的事务一起提交,这就是需要事务传播机制的配置来确定怎么样执行。

即:一个新的事务应该被启动还是被挂起,或者是一个方法是否应该在事务性上下文中运行。

事务传播机制有以下几种:

PROPAGATION_REQUIRED

Spring默认的传播机制,能满足绝大部分业务需求,如果外层有事务,则当前事务加入到外层事务,一块提交,一块回滚。

如果外层没有事务,新建一个事务执行。

PROPAGATION_REQUES_NEW

每次都会新开启一个事务,同时把外层事务挂起,当当前事务执行完毕,恢复上层事务的执行。如果外层没有事务,执行当前新开启的事务即可。

PROPAGATION_SUPPORT

如果外层有事务,则加入外层事务,如果外层没有事务,则直接使用非事务方式执行。完全依赖外层的事务。

PROPAGATION_NOT_SUPPORT

不支持事务,如果外层存在事务则挂起,执行完当前代码,则恢复外层事务,无论是否异常都不会回滚当前的代码。

PROPAGATION_NEVER

不支持外层事务,即如果外层有事务就抛出异常。

PROPAGATION_MANDATORY

与NEVER相反,如果外层没有事务,则抛出异常。

PROPAGATION_NESTED

保存状态保存点,当前事务回滚到某一个点,从而避免所有的嵌套事务都回滚,即各自回滚各自的。

如果子事务没有把异常吃掉,基本还是会引起全部回滚的。

3 事务的隔离级别

3.1 事务并发

并发环境下,多个事务同时运行,会导致以下的问题:

脏读

一个事务读取了被另一个事务改写但尚未提交的数据。

如果这些改变在稍后被回滚了,那么第一个事务读取的数据就会是无效的。

不可重复读

一个事务执行相同的查询两次或两次以上,但每次查询结果都不相同。

通常是由于另一个并发事务在两次查询之间更新了数据。

不可重复读的重点是修改,同样的条件, 你读取过的数据, 再次读取出来发现值不一样了。

幻读

当一个事务(T1)读取几行记录后,另一个并发事务(T2)插入了一些记录时,在后来的查询中,第一个事务(T1)就会发现一些原来没有的额外记录。

幻读的重点在于新增或者删除,同样的条件, 第1次和第2次读出来的记录数不一样。

3.2 隔离级别

在理想状态下,事务之间应满足隔离性,防止上述问题发生。

在标准SQL规范中,定义了以下4个事务隔离级别,不同的隔离级别对事务的处理不同。

ISOLATION_DEFAULT

使用后端数据库默认的隔离级别。

ISOLATION_READ_UNCOMMITTED

读未提交,未授权读取。允许脏读取,其隔离级别最低。

比如事务A和事务B同时进行,事务A在整个执行阶段,会将某数据的值从1开始一直加到10,然后进行事务提交。

此时,事务B能够看到这个数据项在事务A操作过程中的所有中间值(如1变成2,2变成3等),而对这一系列的中间值的读取就是未授权读取。

ISOLATION_READ_COMMITTED

已提交读,授权读取。Oracle默认级别。只允许获取已经提交的数据。

比如事务A和事务B同时进行,事务A进行+1操作,此时,事务B无法看到这个数据项在事务A操作过程中的所有中间值,只能看到最终的10。

另外,如果说有一个事务C,和事务A进行非常类似的操作,只是事务C是将数据项从10加到20,此时事务B也同样可以读取到20。

即授权读取允许不可重复读取。

ISOLATION_REPEATABLE_READ

可重复读。MYSQL默认级别。禁止不可重复读取和脏读取,但是有可能出现幻读。

ISOLATION_SERIALIZABLE

串行化。

最严格的事务隔离级别,它要求所有事务被串行执行,即事务只能一个接一个的进行处理,不能并发执行。

4 事务的实现方式

SpringBoot中推荐使用@Transactional注解管理事务,简单。

4.1 编程式事务管理

在代码中调用beginTransaction()commit()rollback()等事务管理相关的方法进行事务的管理。

4.2 基于TransactionProxyFactoryBean的声明式事务管理

通过配置DataSourceTransactionManagerTransactionProxyFactoryBean进行事务控制。

4.3 基于@Transactional的声明式事务管理

标注在方法上。

@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,rollbackFor=Exception.class)
public void test() {
    //TODO
}

配置说明

  • isolation:指定事务的隔离级别,默认为Isolation.DEFAULT
  • propagation:指定事务的传播性,默认为Propagation.REQUIRED
  • rollbackFor:指定回滚的异常类,可多个
  • noRollbackFor:指定不回滚的异常类,可多个
  • readOnly:指定事务为只读,默认false
  • timeout:指定事务的超时时间,默认不限

注:

Spring中需要显式配置DataSourceTransactionManager及<tx:annotation-driven transaction-manager="myTracnsactionManager"/>

SpringBoot中已经有自动配置了,直接使用即可

4.4 基于Aspect AOP配置事务

通过自定义AOP切点方式配置事务。

5 源码结构

参考文章

6 参考

【SpringBoot系列】八、SpringBoot 中的事务处理

有关Spring事务,看这一篇就足够了

ACID

Spring事务管理之几种方式实现事务

标签: