Spring的事务机制

  1. Spring事务底层是基于数据库事务和AOP机制;
  2. 首先,对于使用了@Transaction 注解的Bean,Spring会创建一个代理对象作为Bean;
    1. 可用在类上和方法上,用在类上代表该类的每个方法都加了这个注解。
  3. 当调用代理对象的方法时,会先判断该方法上是否加了@Transaction 注解;
  4. 如果加了,那么使用事务管理器创建一个数据库连接,并且修改数据库连接的autocommit属性为false,禁止此连接自动提交(这是实现Spring事务非常重要的一步)
  5. 然后执行当前方法(当前方法中可能包含N条SQL语句)
  6. 执行完当前方法后,如果没有出现异常就直接提交事务。
  7. 如果出现了异常,并且该异常是需要回滚的就回滚事务,否则仍然提交事务。
    1. 哪些异常需要回滚可以自己配置
  8. Spring的隔离级别对应的 就是数据库的隔离级别
  9. Spring事务的传播机制是Spring事务自己实现的(也是Spring事务中最复杂的)
  10. Spring事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务。如果传播机制配置为需要新开一个事务,那么实际上就是新建立一个数据库连接,在此新连接上执行SQL。

事务的并发问题

  1. 脏读 (读取未提交数据):指一个事务读取了另外一个事务未提交的数据。
  2. 不可重复读 (前后多次读取,数据内容不一致):在一个事务内读取表中的某一行数据,多次读取结果不同。
  3. 幻读 (前后多次读取,数据总量不一致):是指在一个事务内读取到了别的事务插入的数据,导致前后读取数据总量不一致。

事务的隔离级别

事务的隔离级别从依次为:

  1. SERIALIZABLE:串行化

    该级别是最高级别的隔离级。它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简而言之,SERIALIZABLE 是在每个读的数据行上加锁。

  2. REPEATABLE READ:可重复读(MySQL)

    MySQL 数据库默认的隔离级别。该级别解决了 READ UNCOMMITTED 隔离级别导致的问题。当前事务从不检测并发变更,就是在本事务操作期间看不到其他事务新增的数据行。不过,这会导致另外一个棘手问题“幻读”。
    ==注意==:并发修改值会导致锁表

  3. READ COMMITTED:读取已提交的内容

    大多数数据库系统的默认隔离级别(但是不是 MySQL 的默认隔离级别),满足了隔离的早先简单定义:一个事务开始时,只能“看见”已经提交事务所做的改变,一个事务从开始到提交前,所做的任何数据改变都是不可见的,除非已经提交。这种隔离级别也支持所谓的“不可重复读”。这意味着用户运行同一个语句两次,看到的结果是不同的。

  4. READ UNCOMMITTED:读取未提交内容(脏读)

    在这个隔离级别,所有事务都可以“看到”未提交事务的执行结果。在这种级别上,可能会产生很多问题,除非用户真的知道自己在做什么,并有很好的理由选择这样做。本隔离级别很少用于实际应用,因为它的性能也不必其他性能好多少,而别的级别还有其他更多的优点。读取未提交数据,也被称为“脏读”

==隔离级别越低,越能支持高并发的数据库操作。==

20220529215828.png

Spring事务的传播机制

多个事务方法相互调用时,事务如何在这些方法间传播。

  1. REQUIRED(PROPAGATION_REQUIRED):默认传播行为。如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入到事务中。
  2. SUPPORTS(PROPAGATION_SUPPORTS):如果当前存在事务就加入到该事务,如果当前不存在事务,就以非事务方式运行。
  3. MANDATORY(PROPAGATION_MANDATORY):如果当前存在事务,就加入该事务。如果当前不存在事务,就抛出异常。
  4. REQUIRES_NEW(PROPAGATION_REQUIRES_NEW):无论当前存不存在事务都创建新事务进行执行,如果当前存在事务则挂起,然后在新事务里执行。
  5. NOT_SUPPORTED(PROPAGATION_NOT_SUPPORTED):以非事务方式运行,如果当前存在事务,就将当前事务挂起。
  6. NEVER(PROPAGATION_NEVER):以非事务方式运行。如果当前存在事务,就抛出异常。
  7. NESTED(PROPAGATION_NESTED):如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则按REQUIRED执行。
    1. 和REQUIRES_NEW的区别:REQUIRES_NEW是新建一个事务并且新开启的这个事务与原有事务无关,而NESTED则是在当前事务(我们把当前事务称之为父事务)中开启一个嵌套事务(称之为子事务)。在NESTED情况下父事务回滚时,子事务也会回滚,子事务回滚,父事务不一定回滚,看子事务抛出的异常父事务所在的方法是如何处理的,如果给吞掉了,那么就不会回滚了。而在REQUIRES_NEW,原有事务回滚,不会影响新开启的事务。
    2. 和REQUIRED的区别:REQUIRED情况下,调用方存在事务时,则被调用方和调用方使用同一事务,那么被调用方出现异常时,由于共用一个事务,无论调用方是否catch其异常,事务都会回滚。而在NESTED情况下,被调用方发生异常时,调用方可以catch其异常,这样只有子事务回滚,父事务不受影响。

Spring中事务的隔离级别

可以根据需求自行配置

20220529225920.png

参考: