论坛首页 Java企业应用论坛

spring事务的传播行为与隔离级别

浏览 7996 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (1) :: 隐藏帖 (7)
作者 正文
   发表时间:2011-01-09  
spring事务的传播行为是面试中经常被问到的问题,要将事务的传播行为与隔离级别熟练的掌握,在实际开发过程中,特别是在并发高、更新数据量大、关系表比较多的情况下,经常会遇到关于事务的问题。
首先,要了解的是什么是数据库的隔离级别。在一个典型的应用中,并发是不可避免的,多个事务并发运行,操作同一个数据来完成任务。并发可能会导致以下问题:
脏读(Dirty read):脏读发生在一个事务读取了被另一个事务改写但还未提交的数据时。如果这些改变在稍后被回滚,那么之前的事务读取的到数据就是无效的。
不可重复读(Nonrepeatable read):不可重复读发生在一个事务执行相同的查询两次或两次以上,但每一次的查询结果不同时。这通常是由于另一个并发的事务在两次查询之间更新了数据。
幻读(Phantom read):幻读是一个事务读取几行记录后,另一个事务插入了一些记录,幻读就发生了。在后来的查询中第一个事务就会发现有一些原来没有的额外的记录。
不可重复读和幻读的差异似乎是一个是更新操作一个是插入操作,这一点也请知道的人指正。

spring的事务隔离级别
ISOLATION_DEFAULT:使用数据库默认的隔离级别。
ISOLATION_READ_UNCOMMITTED:允许读取改变了的还未提交的数据,可能导致脏读、不可重复读和幻读。
ISOLATION_READ COMMITTED:允许并发事务提交之后读取,可以避免脏读,可能导致重复读和幻读。
ISOLATION_REPEATABLE_READ:对相同字段的多次读取结果一致,可导致幻读。
ISOLATION_SERIALIZABLE:完全服从ACID的原则,确保不发生脏读、不可重复读和幻读。
可以根据自己的系统对数据的要求采取适应的隔离级别,因为隔离牵涉到锁定数据库中的记录,对数据正性要求越严格,并发的性能也越差。

spring的事务传播行为
spring事务的传播行为说的是当一个方法调用另一个方法时,事务该如何操作。
PROPAGATION_MANDATORY:该方法必须运行在一个事务中。如果当前事务不存在则抛出异常。
PROPAGATION_NESTED:如果当前存在一个事务,则该方法运行在一个嵌套的事务中。被嵌套的事务可以从当前事务中单独的提交和回滚。如果当前不存在事务,则开始一个新的事务。各厂商对这种传播行为的支持参差不齐,使用时需注意。
PROPAGATION_NEVER:当前方法不应该运行在一个事务中。如果当前存在一个事务,则抛出异常。
PROPAGATION_NOT_SUPPORTED:当前方法不应该运行在一个事务中。如果一个事务正在运行,它将在该方法的运行期间挂起。
PROPAGATION_REQUIRED:该方法必须运行在一个事务中。如果一个事务正在运行,该方法将运行在这个事务中。否则,就开始一个新的事务。
PROPAGATION_REQUIRES_NEW:该方法必须运行在自己的事务中。它将启动一个新的事务。如果一个现有的事务正在运行,将在这个方法的运行期间挂起。
PROPAGATION_SUPPORTS:当前方法不需要事务处理环境,但如果一个事务已经在运行的话,这个方法也可以在这个事务里运行。

在现实的应用中,由于业务上的需要,要求不同表中的数据保持一致,即要求不同表中的数据同时更新或者出错时同时回滚,事务的本质其实就是为了解决这样的问题。

原文出处:http://wujidev.com/archives/243
   发表时间:2011-01-10  
幻读是在不可重读的基础上出来的,如果说他们的区别就是一个是更新操作一个是插入操作的话,幻读和不可重读就属于一类问题了,解决一个,也就解决了两个。他俩的主要区别应该是不可重读强调的是在同一个事务中执行两个select语句,是得到的内容不同。但是幻读强调的重点不是两次select。举个列子:事务1包含了一条select语句和insert语句,而事务2是在事务1的select语句和insert语句之间的时间段内,插入了一条和事务1的insert语句一样的内容,这个时候就会报错(可能报XXX不能重复之类的吧)。这个应该是幻读真真的描述的问题所在。不知道我的理解对不?还请lz给予说明,哈哈
0 请登录后投票
   发表时间:2011-01-10  
choha 写道
幻读是在不可重读的基础上出来的,如果说他们的区别就是一个是更新操作一个是插入操作的话,幻读和不可重读就属于一类问题了,解决一个,也就解决了两个。他俩的主要区别应该是不可重读强调的是在同一个事务中执行两个select语句,是得到的内容不同。但是幻读强调的重点不是两次select。举个列子:事务1包含了一条select语句和insert语句,而事务2是在事务1的select语句和insert语句之间的时间段内,插入了一条和事务1的insert语句一样的内容,这个时候就会报错(可能报XXX不能重复之类的吧)。这个应该是幻读真真的描述的问题所在。不知道我的理解对不?还请lz给予说明,哈哈

这个问题也是我一直没有找到答案的,所以上面加了一句“不可重复读和幻读的差异似乎是一个是更新操作一个是插入操作,这一点也请知道的人指正。 ”,欢迎论坛里对这个问题能够清晰阐述的朋友给个正确的答案,或者大家一起探讨
0 请登录后投票
   发表时间:2011-01-10  
不可重复读和幻读的区别在于解决手段,以下是一个不严谨的解释
对于select * from t where id='xxx',如果其它事务更改了id为xxx的记录,就会导致这一条语句两次读取的内容不一致,要防止不可重复读,只需锁定id为xxx的行就可以

而select * from t where age > 50,如果其它事务更改了别的数据,使原本age不大于50的变成了age>50(同理还有insert一条age>50的记录),那就会使得第二次读取时的结果集里记录多出一部分(或者消失了一部分),就好像产生幻觉了,要防止幻读就不是锁定age>50的行能够解决的,而需要锁定查询涉及到的全集

所以这两个概念不是凭空制订的,他们代表着两个不同的锁定范围,代表这不同的两个数据一致性和性能的平衡,这也正是隔离级别的核心意义
0 请登录后投票
   发表时间:2011-01-10  
非常感谢楼上的解答
0 请登录后投票
   发表时间:2011-01-11  
这个哥们结合了一些例子来阐述LZ说的这个主题,还比较清晰,可以结合起来看一下。
http://vae.iteye.com/blog/476457
0 请登录后投票
   发表时间:2011-03-17  
不可重复读和幻读其实都是一种情况.
这类情况可以分为三类:
1.其它事务插入新事务对本事务的影响
2.其它事务删除................
3.其它事务修改同一条记录对本事务的影响
第3种就是 第二类丢失更新
不知道我说的对不????????
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics