日期:2014-05-16  浏览次数:20419 次

第9章 事务和并发(2)
use TSQLFundamentals2008;
go
--9.3 隔离级别
--隔离级别用于决定如何并发控制用户读写数据的操作。读操作可以是任何检索数据的语句,默认使用共享锁。
--写操作是指任何对表做出修改的语句,需要使用排他锁。
--可以设置的隔离级别有6个read uncommitted(未提交读)、read committed(提交读)、repeatable read
--(可重复读)、serializable(可序列化)、snapshot(快照)以及read committed snapshot(已经提交读隔离)。
--隔离级别越高,读操作请求的锁定就越严格,锁持有的时间也更长;因此,隔离级别越高,一致性也就越高,
--并发性就越低。
--9.3.1 read uncommitted 未提交读
--最低级的隔离级别。读操作不会请求共享锁。如果读操作不请求共享锁,就绝对不会和持有排他锁的写操作
--发生冲突。这意味着读操作可以读取未提交的修改(也称为脏读)。同时也意味着读操作不会妨碍写操作请求排他锁。
--Connection 1 
begin tran
update Production.Products
set unitprice+=1.00 --new value 21.00
where productid=2;
--Connection 2 
set transaction isolation level read uncommitted;
select productid, unitprice --21.00
from Production.Products 
where productid=2;
--9.3.2 read committed 已提交读
--能够防止脏读的最低隔离级别是read committed,这也是所有版本的SQL Server默认使用的隔离级别。这个
--隔离级别只允许读取已经提交过的修改。他要求读操作必须获得共享锁才能进行操作,从而防止读取未提交的修改。这
--意味着,如果写操作持有排他锁,读操作做出的共享锁请求就会和写操作发生冲突,所以读操作不得不等待。
--与read uncommitted不同,在read committed隔离级别下,不会读取脏数据。相反,
--只能读取已经提交过的修改。
--按照锁的持有时间来说,在read committed隔离级别中,读操作一完成,就立即释
--放资源上的共享锁。读操作不会在事务持续时间内保留共享锁;实际上设置在语句
--结束前也不能一直保留共享锁。这意味着在一个事务处理内部对相同的数据资源的
--两个读操作之间,没有共享锁会锁定该资源。因此,其他事务可以在两个读操作之
--间更改数据资源,读操作因而可能每次得到不同的取值。这种现象称为不可重复读
--(non-repeatable read)或不一致的分析(inconsistent analysis)。
--9.3.3 Repeatable Read可重复读
--如果想保证在事务内部进行的两个操作之间,其他任何事务都不能修改由当前事务读取
--的数据,则需要把隔离级别升级为repeatable read。在这种隔离级别下,事务中的读
--操作不但需要获得共享锁才能读取数据,而且获得的共享锁将一直保持到事务完成为止。
--这意味着一旦获得数据资源上的共享锁以读取数据,在事务完成之前,没有其他事务能够
--获得排他锁以更改这一数据资源。这样,就可以保证实现可重复的读取,或一致的分析。
--Connection 1
set transaction isolation level repeatable read;

begin tran;
select productid, unitprice
from Production.Products
where productid = 2;
--Connection 2
update Production.Products
set unitprice = unitprice + 10
where productid = 2;
--repeatable read隔离级别能够防止的另一种并发负面影响是丢失更新(lost update),
--而较低的隔离级别则不能防止这种问题。丢失更新是指当两个事务读取了同一个值,然
--后基于最初读取的值进行计算,接着再更新该值,就会发生丢失更新的问题。
--9.3.4 SERIALIZABLE 可序列化
--事务只锁定查询第一次运行时找到的那些数据资源,而不会锁定查询结果范围以外的其他
--行。因此,在同一事物中进行第二次读取之前,如果其他事务插入了新行,而且新行也
--能满足读操作的查询过滤条件,那么这些新行也会出现在第二次读操作返回的结果中。这些
--新行称为幻影(phantom),这种读操作也称为幻读(phantom read)。
--Serializable隔离级别比repeatable read增加了一个新内容———逻辑上,这个隔离级别会
--让读操作锁定满足查询搜索条件的键的整个范围.这就意味着读操作不仅锁定了满足查询
--搜索条件的现有的那些行,还锁定可未来可能满足查询搜索条件的行.或者更准确地说,如果
--其他事务视图增加能够满足读操作的查询搜索条件的新行,当前事务就会阻塞这样的新行.
--Connection 1
set transaction isolation level serializable 
begin tran;
select productid, unitprice
from Production.Products;
commit tran
--Connection 2
insert into Production.Products
(productname, supplierid,categoryid,unitprice,discontinued)
values('Product ABCDE', 1, 1, 20.00, 0);
--9.3.5 snapshot快照 隔离级别
--基于快照的隔离级别下,读操作不需要使用共享锁,所以即使请求的数据被其他事务以排他
--锁锁定,读操作也不会等待.
--在snapshot隔离级别下,当读取数据时,可以保证操作读取的行是事务开始时可用的最后提交的版本.
--快照隔离级别会带来性能上的开销.
--repeatable read和serializable隔离级别是通过产生死锁状态而避免更新冲突的,snapshot
--隔离级别也能够避免更新冲突,但与前两种隔离级别不同,当检测到更新冲突时,snapshot隔离
--级别的快照事务将因失败而终止。snapshot使用行版本控制检查更新。