数据库事务隔离级别与封锁协议
原文链接 http://www.xiangguo.li/sql_and_nosql/2015/01/01/database
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。
{% include JB/setup %}
一、事务的4个基本特征
- 原子性 (Atomicity ) 要么全执行,要么都不执行。
- 一致性( Consistency ) 事务在系统完整性中实施一致性,这通过保证系统的任何事务最后都处于有效状态来实现。
- 隔离性 ( Isolation) 在隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。
- 持久性 (Durabilily) 持久性意味着一旦事务执行成功,在系统中产生的所有变化将是永久的。
二、为什么需要对事务并发控制
如果不对事务进行并发控制,我们看看数据库并发操作是会有那些异常情形
- 丢失更新(Lost update) 两个事务都同时更新一行数据,但是第二个事务却中途失败退出,导致对数据的两个修改都失效了。
- 脏读(Dirty Reads) 一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交。这是相当危险的,因为很可能所有的操作都被回滚。
- 非重复读(Non-repeatable Reads) 一个事务对同一行数据重复读取两次,但是却得到了不同的结果。同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。
- 二类丢失更新(Second lost updates problem) 无法重复读取的特例。有两个并发事务同时读取同一行数据,然后其中一个对它进行修改提交,而另一个也进行了修改提交。这就会造成第一次写操作失效。
- 幻像读(Phantom Reads) 事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查
三、数据库的隔离级别
为了兼顾并发效率和异常控制,在标准SQL规范中,定义了4个事务隔离级别,(ORACLE和SQLSERER对标准隔离级别有不同的实现 )
- 未提交读(Read Uncommitted) 直译就是"读未提交",意思就是即使一个更新语句没有提交,但是别 的事务可以读到这个改变.这是很不安全的。允许任务读取数据库中未提交的数据更改,也称为脏读。
- 提交读(Read Committed) 直译就是"读提交",可防止脏读,意思就是语句提交以后即执行了COMMIT以后 别的事务就能读到这个改变. 只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别
- 可重复读(Repeatable Read): 直译就是"可以重复读",这是说在同一个事务里面先后执行同一个查询语句的时候,得到的结果是一样的.在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读
- 串行读(Serializable) 直译就是"序列化",意思是说这个事务执行的时候不允许别的事务并发执行. 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞
四,隔离级别对并发的控制
下表是各隔离级别对各种异常的控制能力。
LU丢失更新DR脏读NRR非重复读SLU二类丢失更新PR幻像读 未提交读RUYYYYY 提交读RCNNYYY 可重复读RRNNNNY 串行读SNNNNN
五、并发一致性问题的解决办法
封锁(Locking)
封锁是实现并发控制的一个非常重要的技术。所谓封锁就是事务T在对某个数据对象例如表、记录等操作之前,先向系统发出请求,对其加锁。加锁后事务T就对该 数据对象有了一定的控制,在事务T释放它的锁之前,其它的事务不能更新此数据对象。 基本的封锁类型有两种:排它锁(Exclusive locks 简记为X锁)和共享锁(Share locks 简记为S锁)。
排它锁又称为写锁。若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。这就保证了其它事务在T释放A上的锁之前不能再读取和修改A。
共享锁又称为读锁。若事务T对数据对象A加上S锁,则其它事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这就保证了其它事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
封锁协议
在 运用X锁和S锁这两种基本封锁,对数据对象加锁时,还需要约定一些规则,例如应何时申请X锁或S锁、持锁时间、何时释放等。我们称这些规则为封锁协议 (Locking Protocol)。对封锁方式规定不同的规则,就形成了各种不同的封锁协议。下面介绍三级封锁协议。三级封锁协议分别在不同程度上解决了丢失的修改、不 可重复读和读"脏"数据等不一致性问题,为并发操作的正确调度提供一定的保证。下面只给出三级封锁协议的定义,不再做过多探讨。
- 级封锁协议是:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。 1级封锁协议可防止丢失修改,并保证事务T是可恢复的。在1级封锁协议中,如果仅仅是读数据不对其进行修改,是不需要加锁的,所以它不能保证可重复读和不 读"脏"数据。
- 级封锁协议是:1级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁。2级封锁协议除防止了丢失修改,还可进一步防止读"脏"数据。
- 级封锁协议是:1级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。3级封锁协议除防止了丢失修改和不读'脏'数据外,还进一步防止了不可重复读。
六、一般处理并发问题时的步骤:
- 开启事务。
- 申请写权限,也就是给对象(表或记录)加锁。
- 假如失败,则结束事务,过一会重试。
- 假如成功,也就是给对象加锁成功,防止其他用户再用同样的方式打开。
- 进行编辑操作。
- 写入所进行的编辑结果。
- 假如写入成功,则提交事务,完成操作。
- 假如写入失败,则回滚事务,取消提交。
- (7.8)两步操作已释放了锁定的对象,恢复到操作前的状态。