事务传播特性和隔离级别

Posted 慢慢,喜欢

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了事务传播特性和隔离级别相关的知识,希望对你有一定的参考价值。

 事务的四大特性

1.原子性(Atomicity):事务不可再分,要么都执行,要么都不执行。
2.一致性(Consistency):事务执行前后,数据的完整性保持一致,即修改前后数据总量是一样的大概。
3.隔离性(Isolation):一个事务执行过程中,不会受到其他事务干扰。
4.持久性(Durability):事务一旦结束,对数据库的影响是永久的。数据持久化到数据库中。在并行程序中可能会出现的问题

脏读:当 A事务 读取 B事务 未提交的数据后,B事务 回滚,导致 A事务 读取到的数据为脏数据。
不可重复读:A事务 读取第一次读取数据后,B事务 对该数据进行了修改并提交,A事务 再去读取数据时,前后数据结果不一致。
幻读:A事务 读取第一次读取数据后,B事务 又插入或删除了新的数据并提交,A事务 再去读取数据时,前后结果不一致。
事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如 SQL、C++ 或 Java)书写的用户程序的执行所引起,并用形如 begin transaction 和 end transaction 语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。例如:在关系数据库中,一个事务可以是一条 SQL 语句,一组 SQL 语句或整个程序。

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

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

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

 

2.Non-repeatable Read(不可重复读两次读取到的数据不同

假设事务 A 读取了一行数据,接下来事务 B 改变了这行数据,之后事务 A 再一次读取该行数据,结果就是事务 A 两次读取到的数据不同。

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

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

 

三、事务隔离级别(Isolation)
JDBC 规范增加了隔离级别,来满足了 SQL:2003 定义的 4 种事务隔离级别。在安装mysql时,安装默认的隔离级别就是:可重复读。来查看当前隔离级别。隔离级别从最宽松到最严格,排序如下所示:

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

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

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

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

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

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

1.REQUIRED
@Transactional(propagation=Propagation.REQUIRED)
如果当前有事务,加入到这个事务中。如果当前没有事务,就新建一个事务。

2.REQUIRES_NEW
@Transactional(propagation=Propagation.REQUIRES_NEW)
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务。表示当前方法必须运行在它自己的事务中。如果使用 JTATransactionManager 的话,则需要访问 TransactionManager。

3.MANDATORY
@Transactional(propagation=Propagation.MANDATORY)
表示该方法必须在事务中运行,如果当前不存在事务,则会抛出一个异常。不会主动开启一个事务。

4.NEVER
@Transactional(propagation=Propagation.NEVER)
表示该方法不应该运行在事务上下文中,如果当前正有一个事务在运行,则会抛出异常。(与Propagation.MANDATORY相反)。

5.SUPPORTS
@Transactional(propagation=Propagation.SUPPORTS)
表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么这个方法会在这个事务中运行。

6.NOT_SUPPORTED
@Transactional(propagation=Propagation.NOT_SUPPORTED)
表示该方法不应该运行在事务中,如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用 JTATransactionManager 的话,则需要访问 TransactionManager。

7.NESTED
@Transactional(propagation=Propagation.NESTED)
表示如果当前已经存在事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前不存在事务,那么其行为等价于 Propagation.REQUIRED。嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

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

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

 

 

事务的隔离级别和传播特性

脏读:当一个事务读取另一个事务未提交的内容,之后由于另一个事务出现了异常回滚了事务,结果造成读取的数据不一致

不可重复读:指一个事务多次读取同一数据,而另一个事务多次对数据进行了修改的操作,这样就导致了第一个事务每次读取的数据不一样,

幻读:当事务一对整张表的数据进行操作时对其进行了新增行,而另一个事务对其进行了删除行,而这时事务一本身对其进行了新增行然而发现并没有对其新增行而产生了幻觉

脏读与不可重复读的区别:脏读是对没有提交的数据进行查询,不可重复读是对已经提交的数据进行的查询

不可重复读与幻读的区别:不可重复读针对的时update操作,幻读一般是insert和delete操作

事务的隔离级别就是用来解决脏读、不可重复读和幻读问题

事务的隔离级别一般有四种(spring提供了五种):

1.DEFAULT   默认使用数据库的隔离级别

2.READ_UNCOMMITTED  能读取还未提交的事务,不能解决脏读、不可重复度和幻读

3.READ_COMMITTED  只能读取已经提交的事务,能解决脏读,不能解决不可重复读和幻读,一般使用此隔离级别

4.REPEATABLE_READ   当一个事务读取这个数据时会对其进行加锁处理,防止其他事务对数据进行修改。重复读取(REPEATABLE_READ)的意思,读取了一条数据,这个事务不结束,别的事务就不可以改这条记录,这样就解决了脏读、不可重复读的问题,但是幻读的问题还是无法解决

5.SERLALIZABLE 串行化,最高的事务隔离级别,不管多少事务,挨个运行完一个事务的所有子事务之后才可以执行另外一个事务里面的所有子事务,这样就解决了脏读、不可重复读和幻读的问题了

事务的传播特性:指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。

一共有七种传播行为:
1.PROPAGATION_REQUIRED  如果当前方法存在一个事务,则将该方法置于同一个事物中,如果之前不存在事务,则另新开启一个事物(delete ,insert update)

2.PROPAGATION_SUPPORTS 如果当前方法存在一个事务,则将该方法置于同一个事物中,如果之前不存在事务,则进行非事务执行(select)

3.PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。

4.PROPAGATION_REQUIRES_NEW 使用PROPAGATION_REQUIRES_NEW,需要使用 JtaTransactionManager作为事务管理器。 

它会开启一个新的事务。如果一个事务已经存在,则先将这个存在的事务挂起。

5.PROPAGATION_NOT_SUPPORTED PROPAGATION_NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务。使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作为事务管理器。

6.PROPAGATION_NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常。

7.PROPAGATION_NESTED 如果一个活动的事务存在,则运行在一个嵌套的事务中。 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行

 

以上是关于事务传播特性和隔离级别的主要内容,如果未能解决你的问题,请参考以下文章

数据库的特性与隔离级别和spring事务的传播机制和隔离级别

MYSQL的事务隔离级别,MVCC,readView和版本链小结

重新理解mysql的锁事务隔离级别及事务传播行为

数据库事务的四大特性以及事务的隔离级别-与-Spring事务传播机制&隔离级别

事务传播特性和隔离级别

事务的隔离级别和传播特性