事务隔离级别

首先说明一下数据库中数据一致性的几个问题,包括脏读(Dirty reads),丢失更新(Lost updates),不可重复读(Nonrepeatable reads),幻象(Phantoms)。

 脏读(Dirty reads):是指读取到未提交的数据。一个进程修改数据,而另一个进程在修改数据进程未提交之前读取了数据。这样第二个进程读取到了不一致的数据。

丢失更新(Lost updates):一个进程读取数据,在原数据的基础上做了一些计算处理,然后将原数据更新为计算后的数据。如果有多个进程来进行这样的操作,一个修改有可能被另一个修改覆盖掉。

不可重复读(Nonrepeatable reads):同一事务两次独立的读取相同数据得到不同的值。这种情况可以发生在当一个进程读取数据的过程中,另一个进程修改了第一个进程所要读取的数据。

幻象(Phantoms):当一个进程对一定范围内的行执行操作时,另一个进程对相同范围内的行执行相反的操作。例如,一个进程通过一些过滤器(可以理解为一些where条件)删除了所有行,在这个删除事务中另一个进程插入了一条满足条件的新行。新行被认为是幻影。

下面说明一下在SQL2005中事务了六种隔离级别(在2000中只有4种隔离级别)。

Read Uncommitted (未提交读) READ_UNCOMMITTED
当工作在未提交读隔离级别下的时候,读取数据的用户不需要共享锁。因此从来不会与其它修改数据会话冲突。用户可以在排外锁下读取数据,同时不会干涉修改数据的进程。当然这种级别的读取数据很可能会读取到未提交的数据。换句话锁,脏读是可以发生的,也包括其它的并发问题。为提交读是最差的隔离方式在一致性方面,但在并发问题上却是最好的。
Read Committed (已提交读) READ_COMMITTED
已提交读是SQL Server默认的隔离级别。在这种级别下,进程需要一个共享锁来读取数据并且在读取完数据以后马上释放,不是等到事务终止的时候。这就以为着脏读不可能发生。用户只可以读到修改并提交的数据。然而其它并发问题在这种隔离级别下还是会发生的。
Repeatable Read (可重复读) REPEATABLE_READ
在可重复读隔离级别下工作的进程也需要一个共享锁来读取数据,意味着脏读在这种级别下是不能发生的。但是与已提交读不同,可重复读会在事务终止后释放共享锁。用户可以在多次读取数据的时候读取到相同的数据,因为其它进程不能得到排外锁在用户读取数据的时候。
丢失更新在这种隔离级别下是不能发生的。如果两个进程保留共享锁知道事务终止,同时两个进程试图修改数据,这种情况下会引发死锁,因为每个进程都需要一个排外锁,这样它们就互相阻塞着对方。当SQL Server 发现死锁发生,它会选择一个牺牲品-比如那些执行任务比较少的进程-并将该进程事务回滚。这个进程会得到一个1205的错误,并可以重新发布这个事务。尽管丢失更新不能在可重复读隔离级别下发生,但幻象读还是问题。
Serializable (序列化) SERIALIZABLE
序列化隔离级别类似于可重复读,在其基础上增加了新的方面-活动的事务需要得到键范围锁(Key-range locks)(存在索引的字段)基于查询过滤器。这个申请不仅对读取者同时也包括写者。获得键范围锁意味着用户在逻辑上锁住所有满足查询条件的数据。用户不仅仅锁住了物理上存在的数据同时也锁住了不存在的数据(这里是指满足查询条件的数据后加进来的,这样可以避免幻象读) 。 这种级别可以避免幻象读。
Snapshot(快照) SNAPSHOT TIL  SQL Server 2005
当进程在快照隔离级别下读取数据的时候,进程可以得到最新的具有一致性版本的数据,可以用在事务开始的时候。事务开始的时候在技术上认为当第一条语句执行的时候。无论合适当一个事务要修改一行数据的时候,只要有一个事务运行在快照隔离级别下,SQL Server 需要在修改之前存储一个一致性的版本,不管修改数据的事务是否运行在快照隔离级别下。当一个进程修改了数据,其它运行在快照隔离级别下的进程需要一个旧的具有一致性版本的数据。
工作在快照隔离级别下会有性能上的影响,在修改数据的进程不是工作在快照隔离级别的下时候。因此SQL Server 需要用户打开数据库设置允许工作在快照隔离级别下:ALTER DATABASE testdb SET ALLOW_SNAPSHOT_ISOLATION ON;
如果这个设置被关闭,快照隔离级别在数据库中就不会被允许,行版本也不会被记录。
Read Committed Snapshot (已提交读快照) SQL Server 2005
已提交读快照是一个新的已提交读隔离级别可以被用到每一个基本的数据库上。当用户设置Read_Committed_snapshot 状态为开,所有工作在默认级别(已提交读)级别下的会话实际上会工作在已提交读快照隔离级别下。这是数据库全局行为变化。
已提交读快照和快照隔离级别在两个方面有区别。第一个不同是读者可以得到最新的一致性版本数据在执行语句开始的时候,而不是事务开始的时候。同时这中隔离级别也不会出现更新冲突。
这种隔离级别在将数据从平台间转移获得更早的一致性版本数据特别有用。比如当应用程序从Oracle数据库转移到SQL Server。
 
补充:
可重复读与序列化的区别:序列化与可重复读很类似,只是可重复读会产生幻象,因为将隔离级别设置为可重复读的时候,其它进程可以插入数据进来,这些数据又恰恰满足执行可重复读的事务,这样就产生了幻象。而序列化避免了这一点,在序列化的隔离级别下,其它进程不可以读,也不可以写,这样就避免了幻象
 
下表显示了不同隔离级别允许的并发副作用。
隔离级别脏读不可重复读取幻读

未提交读

已提交读

可重复读

快照

可序列化

有关每个事务隔离级别控制的特定类型的锁或行版本控制的详细信息,请参阅SET TRANSACTION ISOLATION LEVEL (Transact-SQL)。

 

 

附:锁兼容性(FROM SQL Server 2005 联机丛书)

锁兼容性控制多个事务能否同时获取同一资源上的锁。如果资源已被另一事务锁定,则仅当请求锁的模式与现有锁的模式相兼容时,才会授予新的锁请求。如果请求锁的模式与现有锁的模式不兼容,则请求新锁的事务将等待释放现有锁或等待锁超时间隔过期。

posted @ 2012-11-07 17:01  瞭望者  阅读(167)  评论(0)    收藏  举报