SpringBoot的事务机制
Spring的事务机制
- Spring事务底层是基于数据库事务和AOP机制;
- 首先,对于使用了@Transaction 注解的Bean,Spring会创建一个代理对象作为Bean;
- 可用在类上和方法上,用在类上代表该类的每个方法都加了这个注解。
- 当调用代理对象的方法时,会先判断该方法上是否加了@Transaction 注解;
- 如果加了,那么使用事务管理器创建一个数据库连接,并且修改数据库连接的autocommit属性为false,禁止此连接自动提交(这是实现Spring事务非常重要的一步)
- 然后执行当前方法(当前方法中可能包含N条SQL语句)
- 执行完当前方法后,如果没有出现异常就直接提交事务。
- 如果出现了异常,并且该异常是需要回滚的就回滚事务,否则仍然提交事务。
- 哪些异常需要回滚可以自己配置
- Spring的隔离级别对应的 就是数据库的隔离级别
- Spring事务的传播机制是Spring事务自己实现的(也是Spring事务中最复杂的)
- Spring事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务。如果传播机制配置为需要新开一个事务,那么实际上就是新建立一个数据库连接,在此新连接上执行SQL。
事务的并发问题
- 脏读 (读取未提交数据):指一个事务读取了另外一个事务未提交的数据。
- 不可重复读 (前后多次读取,数据内容不一致):在一个事务内读取表中的某一行数据,多次读取结果不同。
- 幻读 (前后多次读取,数据总量不一致):是指在一个事务内读取到了别的事务插入的数据,导致前后读取数据总量不一致。
事务的隔离级别
事务的隔离级别从高到低依次为:
-
SERIALIZABLE:串行化
该级别是最高级别的隔离级。它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简而言之,SERIALIZABLE 是在每个读的数据行上加锁。
-
REPEATABLE READ:可重复读(MySQL)
MySQL 数据库默认的隔离级别。该级别解决了 READ UNCOMMITTED 隔离级别导致的问题。当前事务从不检测并发变更,就是在本事务操作期间看不到其他事务新增的数据行。不过,这会导致另外一个棘手问题“幻读”。
==注意==:并发修改值会导致锁表 -
READ COMMITTED:读取已提交的内容
大多数数据库系统的默认隔离级别(但是不是 MySQL 的默认隔离级别),满足了隔离的早先简单定义:一个事务开始时,只能“看见”已经提交事务所做的改变,一个事务从开始到提交前,所做的任何数据改变都是不可见的,除非已经提交。这种隔离级别也支持所谓的“不可重复读”。这意味着用户运行同一个语句两次,看到的结果是不同的。
-
READ UNCOMMITTED:读取未提交内容(脏读)
在这个隔离级别,所有事务都可以“看到”未提交事务的执行结果。在这种级别上,可能会产生很多问题,除非用户真的知道自己在做什么,并有很好的理由选择这样做。本隔离级别很少用于实际应用,因为它的性能也不必其他性能好多少,而别的级别还有其他更多的优点。读取未提交数据,也被称为“脏读”
==隔离级别越低,越能支持高并发的数据库操作。==

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

参考:
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 程序员小航
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果