【转】数据库的事务隔离级别分析

MicrosoftInternetExplorer402DocumentNotSpecified7.8Normal0

在数据库系统中,隔离 是定义一个操作对数据所做的改变如何/何时对其它的并行 操作可见。 

隔离并不改变锁本身的行为,而是通过实行不同的锁机制实现的。比如是否加锁,加多长时间的锁,加什么类型的锁等。同时,也会影响排它情况下的可见性(见read uncommited)。

隔离级别

数据库系统有四个隔离级别。对数据库使用何种隔离级别要审慎分析,因为

1. 维护一个最高的隔离级别虽然会防止数据的出错,但是却导致了并行度的损失,以及导致死锁出现的可能性增加。

2. 然而,降低隔离级别,却会引起一些难以发现的bug

SERIALIZABLE(序列化)

添加范围锁(比如表锁,页锁等,关于range lock,我也没有很深入的研究),直到transaction A结束。以此阻止其它trasaction B对此范围内的insertupdate等操作。

幻读,脏读,不可重复读等问题都不会发生。

REPEATABLE READ(可重复读)

对于读出的记录,添加共享锁直到transaction A结束。其它transaction B对这个记录的试图修改会一直等待直到trasaction A结束。

可能发生的问题:当执行一个范围查询时,可能会发生幻读。

READ COMMITTED(提交读)

trasaction A中读取数据时对记录添加共享锁,但读取结束立即释放。其它transaction B对这个记录的试图修改会一直等待直到A中的读取过程结束,而不需要整个trasaction A的结束。所以,在trasaction A的不同阶段对同一记录的读取结果可能是不同的。

可能发生的问题:不可重复读。

READ UNCOMMITTED(未提交读)

不添加共享锁。所以其它trasaction B可以在trasaction A对记录的读取过程中修改同一记录,可能会导致A读取的数据是一个被破坏的或者说不完整不正确的数据。

另外,在trasaction A中可以读取到trasaction B(未提交)中修改的数据。比如trasaction BR记录修改了,但未提交。此时,在Trasaction A中读取R记录,读出的是被B修改过的数据。

可能发生的问题:脏读。

问题

我们看到,当执行不同的隔离级别时,可能会发生各种各样不同的问题。下面对它们进行总结并举例说明。

幻读

幻读发生在当两个完全相同的查询执行时,第二次查询所返回的结果集跟第一个查询不相同。

发生的情况:没有范围锁。

例子:

事务1

事务2


INSERT INTO  users 

VALUES ( 3, 'Bob', 27 );

SLECT * FROM users 

WHERE age BETWEEN 10 AND 30


 如何避免:实行序列化隔离模式,在任何一个低级别的隔离中都可能会发生。

不可重复读

在基于锁的并行控制方法中,如果在执行select时不添加读锁,就会发生不可重复读问题。

在多版本并行控制机制中,当一个遇到提交冲突的事务需要回退但却被释放时,会发生不可重复读问题。 

事务1

事务2

SELECT * FROM users WHERE id = 1;



UPDATE users SET age = 21 WHERE id = 1;
COMMIT; 
/* in multiversion concurrency control, or lock-based READ COMMITTED */

SELECT * FROM users
 WHERE id = 1;



COMMIT; /* lock-based REPEATABLE READ */

在上面这个例子中,事务2提交成功,它所做的修改已经可见。然而,事务1已经读取了一个其它的值。在序列化和可重复读的隔离级别中,数据库管理系统会返回旧值,即在被事务2修改之前的值。在提交读和未提交读隔离级别下,可能会返回被更新的值,这就是不可重复读。 

有两个策略可以防止这个问题的发生:

1. 推迟事务2的执行,直至事务1提交或者回退。这种策略在使用锁时应用。

2. 而在多版本并行控制中,事务2可以被先提交。而事务1,继续执行在旧版本的数据上。当事务1终于尝试提交时,数据库会检验它的结果是否和事务1、事务2顺序执行时一样。如果是,则事务1提交成功。如果不是,事务1会被回退。

 脏读

脏读发生在一个事务A读取了被另一个事务B修改,但是还未提交的数据。假如B回退,则事务A读取的是无效的数据。这跟不可重复读类似,但是第二个事务不需要执行提交。 

事务1

事务2

SELECT * FROM users WHERE id = 1;



UPDATE users SET age = 21 WHERE id = 1

SELECT * FROM users
 WHERE id = 1



COMMIT; /* lock-based DIRTY READ */


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/24793148/viewspace-678385/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/24793148/viewspace-678385/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值