转载

Spring事务

Spring的4种事务特性,5种隔离级别,7种传播行为

参考:

MySQL的四种事务隔离级别

透彻的掌握 Spring 中@transactional 的使用

事务逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败.

1.事务特性( ACID

  • 原子性(atomicity) : 强调事务的不可分割。 事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
  • 一致性(consistency) : 事务的执行的前后数据的完整性保持一致。 事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
  • 隔离性(isolation) : 一个事务执行的过程中,不应该受到其他事务的干扰。 同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
  • 持久性(durability) : 事务一旦结束,数据就持久到数据库。 事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

2.如果不考虑隔离性引发安全性问题

  • 脏读 : 一个事务读到了另一个事务的未提交的数据。 事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
  • 不可重复读 : 一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致。 事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
  • 虚幻读 : 一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致。 系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

小结:不可重复读的和幻读很容易混淆,不可重复读侧重于 修改 ,幻读侧重于 新增或删除 。解决不可重复读的问题只需 锁住满足条件的行 ,解决幻读需要 锁表

3.解决读问题: 设置事务隔离级别(5种)

  • DEFAULT : 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.

Mysql 默认:可重复读 select @@tx_isolation
Oracle 默认:已提交读

  • 未提交读(read uncommited) : 脏读,不可重复读,虚读都有可能发生

是最低的事务隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。

  • 已提交读(read commited) : 避免脏读。但是不可重复读和虚读有可能发生

保证一个事物提交后才能被另外一个事务读取。另外一个事务不能读取该事物未提交的数据。

  • 可重复读(repeatable read) : 避免脏读和不可重复读.但是虚读有可能发生.

这种事务隔离级别可以防止脏读,不可重复读。但是可能会出现幻象读。它除了保证一个事务不能被另外一个事务读取未提交的数据之外还避免了以下情况产生(不可重复读)。

  • 串行化(serializable) : 避免以上所有读问题.

这是花费最高代价但最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读之外,还避免了幻象读(避免三种)。

隔离级别 脏读 不可重复读 虚读(幻读)
未提交读 可能 可能 可能
已提交读 不可能 可能 可能
可重复读 不可能 不可能 可能
串行化 不可能 不可能 不可能

4.事务的传播行为(7种)

propagation :事务的传播行为

1.保证在同一个事务中

行为
PROPAGATION_REQUIRED 支持当前事务,如果不存在 就新建一个(默认)
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常

2.保证不在同一个事务中

行为
PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行

5. @Transactional的使用事项

1. rollbackFor

默认情况下,如果在事务中抛出了unchecked异常(继承自 RuntimeException 的异常)或者 Error,则 Spring 将回滚事务;除此之外,Spring 不会回滚事务。

如果在事务中抛出其他类型的异常,并期望 Spring 能够回滚事务,可以指定

rollbackFor = {XException.class, YException.class}

2. @Transactional 只能应用到 public 方法才有效

只有@Transactional 注解应用到 public 方法,才能进行事务管理。这是因为在使用 Spring AOP 代理时,Spring 在调用在图 1 中的 TransactionInterceptor 在目标方法执行前后进行拦截之前, DynamicAdvisedInterceptor (CglibAopProxy 的内部类)的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSource (Spring 通过这个类获取 @Transactional 注解的事务属性配置属性信息)的 computeTransactionAttribute 方法。

Spring事务

这个方法会检查目标方法的修饰符是不是 public,若不是 public,就不会获取 @Transactional 的属性配置信息,最终会造成不会用 TransactionInterceptor 来拦截该目标方法进行事务管理

3. Spring 的 AOP 的自调用问题

在 Spring 的 AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring 生成的代理对象来管理,这会造成自调用问题。若同一类中的其他没有@Transactional 注解的方法内部调用有@Transactional 注解的方法,有@Transactional 注解的方法的事务被忽略,不会发生回滚

原文  https://segmentfault.com/a/1190000020798887
正文到此结束
Loading...