Spring事务的隔离级别和传播行为

Spring事务的隔离级别和传播行为

事务(Transaction)是访问并可能更新数据库中各类数据项的一个程序执行单元(unit)。事务一般由高级数据库操纵语言或编程语言(如SQL、C++或Java)书写的用户程序的执行所引发,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操做组成。例如:在关系数据库中,一个事务能够是一条SQL语句,一组SQL语句或整个程序。程序员

事务是恢复和并发控制的基本单位。

事务隔离级别定义了在一个事务中,哪些数据是对当前执行的语句“可见”的。在并发访问数据库时,事务隔离级别定义了多个事务之间对于同个目标数据源访问时的可交叉程度。spring

1、可交叉程度

1️⃣Dirty Read(脏读) 看到的数据则是不正确的数据库

当一个事务能看见另一个事务未提交的数据时,就称为脏读。若是这个事务被回滚了而不是提交了,那么其它事务看到的数据则是不正确的,是“脏”的。编程

img

2️⃣Non-repeatable Read(不可重复读) 两次读取到的数据不一样并发

假设事务A读取了一行数据,接下来事务B改变了这行数据,以后事务A再一次读取这行数据,结果就是事务A两次读取到的数据不一样。编程语言

img

3️⃣Phantom Read(幻读) 发现多出来一条数据函数

假设事务A经过一个 where 条件读取到了一个结果集,事务B这时插入了一条符合事务A的 where 条件的数据,以后事务A经过一样的 where 条件再次查询时,发现多出来一条数据。atom

img

2、事务隔离级别(Isolation)

JDBC 规范增长了隔离级别,来知足了 SQL:2003 定义的 4 种事务隔离级别。在安装MySQL时,安装默认的隔离级别就是:可重复读。能够经过 select @@global.tx_isolation; 来查看当前隔离级别。隔离级别从最宽松到最严格,排序以下所示:代理

1️⃣TRANSACTION_NONE
这意味着当前的 JDBC 驱动不支持事务,也意味着这个驱动不符合 JDBC 规范。code

2️⃣READ_UNCOMMITTED(读未提交)
容许事务看到其它事务修改了但未提交的数据,这意味着有多是脏读、不可重复读或者幻读。

3️⃣READ_COMMITTED(读提交)
一个事务在未提交以前,所作的修改不会被其它事务所看见。这能避免脏读,但避免不了不可重复读和幻读。

4️⃣REPEATABLE_READ(可重复读取) MySQL默认的事务隔离级别
避免了脏读和不可重复读,但幻读依然是有可能发生的。

5️⃣SERIALIZABLE(序列化)
避免了脏读、不可重复读以及幻读。

img

3、Propagation事务传播行为

Propagation属性用来枚举事务的传播行为。所谓事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。Spring支持7种事务传播行为,默认为REQUIRED。

1️⃣REQUIRED
REQUIRED是经常使用的事务传播行为。若是当前没有事务,就新建一个事务,若是已经存在一个事务中,加入到这个事务中。

2️⃣SUPPORTS
SUPPORTS表示当前方法不须要事务上下文,可是若是存在当前事务的话,那么这个方法会在这个事务中运行。

3️⃣MANDATORY
MANDATORY表示该方法必须在事务中运行,若是当前事务不存在,则会抛出一个异常。不会主动开启一个事务。

4️⃣REQUIRES_NEW
REQUIRES_NEW表示当前方法必须运行在它本身的事务中。一个新的事务将被启动,若是存在当前事务,在该方法执行期间,当前事务会被挂起(若是一个事务已经存在,则先将这个存在的事务挂起)。若是使用JTATransactionManager的话,则须要访问TransactionManager。

5️⃣NOT_SUPPORTED
NOT_SUPPORTED表示该方法不该该运行在事务中,若是存在当前事务,在该方法运行期间,当前事务将被挂起。若是使用JTATransactionManager的话,则须要访问TransactionManager。

6️⃣NEVER
NEVER表示当前方法不该该运行在事务上下文中,若是当前正有一个事务在运行,则会抛出异常。

7️⃣NESTED
NESTED表示若是当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务能够独立于当前事务进行单独地提交或回滚。若是当前事务不存在,那么其行为与REQUIRED同样。嵌套事务一个很是重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所作的动做。而内层事务操做失败并不会引发外层事务的回滚。

综上所述,NESTED和REQUIRES_NEW很是类似,都是开启一个属于它本身的新事务。使用REQUIRES_NEW时,内层事务与外层事务就像两个独立的事务同样,一旦内层事务进行了提交后,外层事务不能对其进行回滚。当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行。两个事务互不影响,两个事务不是一个真正的嵌套事务,同时它还须要JTA事务管理器的支持。

使用NESTED时,外层事务的回滚能够引发内层事务的回滚。而内层事务的异常并不会致使外层事务的回滚,它是一个真正的嵌套事务。嵌套事务开始执行时, 它将取得一个 savepoint,若是这个嵌套事务失败, 将回滚到此savepoint。潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。

4、Spring事务的基本原理

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,Spring是没法提供事务功能的。对于纯JDBC操做数据库,想要用到事务,能够按照如下步骤进行:

  1. 获取链接 Connection con = DriverManager.getConnection();
  2. 开启事务 con.setAutoCommit(true/false);
  3. 执行 CRUD;
  4. 提交事务/回滚事务 con.commit()/con.rollback();
  5. 关闭链接 con.close()。

使用Spring的事务管理功能后,程序员能够再也不写步骤 2 和 4 的代码,而是由 Spirng 自动完成。Spring是如何CRUD以前和以后开启事务和关闭事务的?解决这个问题,也就能够从总体上理解Spring的事务管理实现原理了。下面简单地介绍下,注解方式为例子:

  1. 配置文件开启注解驱动,在相关的类和方法上经过注解@Transactional标识。
  2. Spring 在启动的时候会去解析生成相关的bean,这时候会查看拥有相关注解的类和方法,而且为这些类和方法生成代理,并根据@Transactional的相关参数进行相关配置注入,这样就在代理中把相关的事务实现了(开启正常提交事务,异常回滚事务)。
  3. 真正的数据库层的事务提交和回滚是经过binlog或者redo log实现的。

5、原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)

事务最经典的例子就是转帐了。假如小明要给小红转帐100元,这个转帐会涉及到两个关键操做就是:将小明的余额减小100元,将小红的余额增长100元。万一在这两个操做之间忽然出现错误(如银行系统崩溃等),致使小明余额减小而小红的余额没有增长,这样就不对了。事务就是保证这两个关键操做要么都成功,要么都要失败。

img

1️⃣原子性(atomicity)。一个事务是一个不可分割的工做单位,事务中包括的操做要么都作,要么都不作。
2️⃣一致性(consistency)。事务必须是使数据库从一个一致性状态变到另外一个一致性状态。一致性与原子性是密切相关的。
3️⃣隔离性(isolation)。一个事务的执行不能被其余事务干扰。即一个事务内部的操做及使用的数据对并发的其余事务是隔离的,并发执行的各个事务之间不能互相干扰。
4️⃣持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其余操做或故障不该该对其有任何影响。

(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其余操做或故障不该该对其有任何影响。

转载自:原文连接

相关文章
相关标签/搜索