转载

数据库事务隔离级别

一,事务的4个基本特征 

Atomic(原子性): 
事务中包含的操作被看做一个逻辑单元,这个逻辑单元中的操作要 
么全部成功,要么全部失败。 

Consistency(一致性): 
只有合法的数据可以被写入数据库,否则事务应该将其回滚到最初 
状态。 

Isolation(隔离性): 
事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正 
确性和完整性。同时,并行事务的修改必须与其他并行事务的修改 
相互独立。 

Durability(持久性): 
事务结束后,事务处理的结果必须能够得到固化。 

在事务处理的ACID属性中,一致性是最基本的属性,其它的三个属性都为了保证一致性而存在的。

一致性,指的是数据处于一种有意义的状态,这种状态是语义上的而不是语法上的。最常见的例子是转帐。例如从帐户A转一笔钱到帐户B上,

如果帐户A上的钱减少了,而帐户B上的钱却没有增加,那么我们认为此时数据处于不一致的状态。

在数据库实现中,在同一个事务内部的一组操作必须全部执行成功(或者全部失败),这就是事务处理的原子性。


为了实现原子性,需要通过日志:将所有对数据的更新操作都写入日志,如果一个事务中的一部分操作已经成功,但以后的操作,

由于断电/系统崩溃/其它的软硬件错误而无法继续,则通过回溯日志,将已经执行成功的操作撤销,从而达到“全部操作失败”的目的。

最常见的场景是,数据库系统崩溃后重启,此时数据库处于不一致的状态,必须先执行一个crash recovery的过程:读取日志进行REDO

(重演将所有已经执行成功但尚未写入到磁盘的操作,保证持久性),再对所有到崩溃时尚未成功提交的事务进行UNDO(撤销所有执

行了一部分但尚未提交的操作,保证原子性)。crash recovery结束后,数据库恢复到一致性状态,可以继续被使用。

日志的管理和重演是数据库实现中最复杂的部分之一。如果涉及到并行处理和分布式系统(日志的复制和重演是数据库高可用性的基础),会比上述场景还要复杂得多。


但是,原子性并不能完全保证一致性。在多个事务并行进行的情况下,即使保证了每一个事务的原子性,仍然可能导致数据不一致的结果。例如,

事务1需要将100元转入帐号A:先读取帐号A的值,然后在这个值上加上100。但是,在这两个操作之间,另一个事务2修改了帐号A的值,为它

增加了100元。那么最后的结果应该是A增加了200元。但事实上, 事务1最终完成后,帐号A只增加了100元,因为事务2的修改结果被事务1覆盖掉了。


为了保证并发情况下的一致性,引入了隔离性,即保证每一个事务能够看到的数据总是一致的,就好象其它并发事务并不存在一样。用术语来说

,就是多个事务并发执行后的状态,和它们串行执行后的状态是等价的。怎样实现隔离性,已经有很多人回答过了,原则上无非是两种类型的锁:


一种是悲观锁,即当前事务将所有涉及操作的对象加锁,操作完成后释放给其它对象使用。为了尽可能提高性能,发明了各种粒度(数据库级/表级/行级……)/各种性质

(共享锁/排他锁/共享意向锁/排他意向锁/共享排他意向锁……)的锁。为了解决死锁问题,又发明了两阶段锁协议/死锁检测等一系列的技术。


一种是乐观锁,即不同的事务可以同时看到同一对象(一般是数据行)的不同历史版本。如果有两个事务同时修改了同一数据行,那么在较晚的事务提交时进行冲突检测。

实现也有两种,一种是通过日志UNDO的方式来获取数据行的历史版本,一种是简单地在内存中保存同一数据行的多个历史版本,通过时间戳来区分。

二,为什么需要对事务并发控制 

如果不对事务进行并发控制,我们看看数据库并发操作是会有那些异常情形

Lost update: 
两个事务都同时更新一行数据,但是第二个事务却中途失败退出, 
导致对数据的两个修改都失效了。

Dirty Reads: 
一个事务开始读取了某行数据,但是另外一个事务已经更新了此数 
据但没有能够及时提交。这是相当危险的,因为很可能所有的操作 
都被回滚。 

Non-repeatable Reads: 
一个事务对同一行数据重复读取两次,但是却得到了不同的结果。 

Second lost updates problem: 
无法重复读取的特例。有两个并发事务同时读取同一行数据,然后其 
中一个对它进行修改提交,而另一个也进行了修改提交。这就会造成 
第一次写操作失效。 

Phantom Reads: 
事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查 
询中未出现的数据(这里并不要求两次查询的SQL语句相同)。这是 
因为在两次查询过程中有另外一个事务插入数据造成的。 

三, 数据库的隔离级别 

为了兼顾并发效率和异常控制,在标准SQL规范中,定义了4个事务隔
离级别,(ORACLE和SQLSERER对标准隔离级别有不同的实现 )

Read Uncommitted: 
直译就是"读未提交",意思就是即使一个更新语句没有提交,但是别 
的事务可以读到这个改变.这是很不安全的. 

Read Committed: 
直译就是"读提交",意思就是语句提交以后即执行了COMMIT以后 
别的事务就能读到这个改变. 

Repeatable Read: 
直译就是"可以重复读",这是说在同一个事务里面先后执行同一个 
查询语句的时候,得到的结果是一样的. 

Serializable: 
直译就是"序列化",意思是说这个事务执行的时候不允许别的事务 
并发执行. 

四,隔离级别对并发的控制
 

下表是各隔离级别对各种异常的控制能力:

 

 LUDRNRRSLUPR
RUNYYYY
RCNNYYY
RRNNNNY
SNNNNN










文章最后发布于: 2015-11-14 10:53:45
展开阅读全文
0 个人打赏

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 酷酷鲨 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览