Sql Server 中锁的概念(2)
1.一般大家都对事务的四种隔离模式比较熟悉,从松到严依次是:
- 读取未提交(Read uncommitted):处于此模式下可能会出现脏读、幻象读、不可重复读
- 读取已提交(Read committed):处于此模式下可能会出现幻象读、不可重复读
- 可重复读(Repeatable read):处于此模式下可能会出现幻象读
- 串行(Serialize):不会出现幻象读
那么脏读、幻象行、不可重复读是什么意思呢?
- 脏读:其它的事务(执行单个 select 语句也算一个事务)可以读取到某个事务更新(包括插入和删除)了但未提交的数据。脏读是应用中应该避免的,因为读取的是不可靠的数据(我觉得把这个叫做幻象行更形象,实际却不是)。一般数据库不会设定为这个模式,但有时候也会用到。脏读的好处是读取时不会对表或记录加锁,可以绕开写队列的排队,避免了等待。如在一个更新特别频繁的表中要选择表中所有的数据,就可以显示指定隔离级别:
select .... at isolation 0
- 不可重复读:这是描述在同一个事务中两条一模一样的 select 语句的执行结果的比较。如果前后执行的结果一样,则是可重复读;如果前后的结果可以不一样,则是不可重复读。这个特性从字面上也能看出来。
不可重复读的模式下首先不会出现脏读,即读取的都是已提交的数据。在一个事务中,读取操作是不会加排他锁的,当下一条一模一样的 select 语句的执行时,命中的数据集可能已经被其它事务修改了,这时候,还能读到相同的内容吗?
因此,要达到可重复读的效果,数据库需要做更多的事情,比如,对读取的数据行加共享锁,并保持到事务结束,以禁止其它事务修改它。这样会降低数据库的性能。而隔离级别的串行则比可重复读更严格。一般数据库的的隔离级别只设置到读取已提交。这是兼顾了可靠性和性能的结果。
上面还只提到了对命中的数据行加锁,以防止其它事务修改它。但没有提到,如果其它事务增加了符合条件的数据行怎么办?有些数据库对这种情况新定义了两个级别:读取稳定性和游标稳定性。前者不限制新增符合条件的数据行,而后者则阻止新增这样的数据行。
- 幻象读:是指两次执行同一条 select 语句会出现不同的结果,第二次读会增加一数据行,并没有说这两次执行是在同一个事务中。一般情况下,幻象读应该正是我们所需要的。但有时候却不是,如果打开的游标,在对游标进行操作时,并不希望新增的记录加到游标命中的数据集中来。隔离级别为 游标稳定性 的,可以阻止幻象读。
2.存储过程:SET Transaction Isolation Level Read语法的四种情况
这几天一直在弄存储过程,现在在这里跟大伙共享下资料:
SET Transaction Isolation Level Read UNCOMMITTED
使用这句东东呢可以分为四种情况,现在就在这里逐一介绍:
第一种情况:
READ COMMITTED
这句的作用是:
指定在读取数据时控制共享锁以避免脏读,但数据可在事务结束前更改,从而产生不可重复读取或幻像数据。该选项是 SQL Server 的默认值。
第二种情况:
READ UNCOMMITTED
这句的作用是:
执行脏读或0级隔离锁定,这表示不发出共享锁,也不接受排它锁。当设置该选项时,可以对数据执行未提交读或脏读;在事务结束前可以更改数据内的数值,行也可以出现在数据集中或从数据集消失。该选项的作用与在事务内所有语句中的所有表上设置 NOLOCK 相同。这是四个隔离级别中限制最小的级别。
第三种情况:
REPEATABLE READ
这句的作用是:
锁定查询中使用的所有数据以防止其他用户更新数据,但是其他用户可以将新的幻像行插入数据集,且幻像行包括在当前事务的后续读取中。因为并发低于默认隔离级别,所以应只在必要时才使用该选项。
第四种情况:
SERIALIZABLE
这句的作用是:
在数据集上放置一个范围锁,以防止其他用户在事务完成之前更新数据集或将行插入数据集内。这是四个隔离级别中限制最大的级别。因为并发级别较低,所以应只在必要时才使用该选项。该选项的作用与在事务内所有 SELECT 语句中的所有表上设置 HOLDLOCK 相同。