SQL Server - 关于可序列化隔离级别

时间:2017-05-20 10:46:39

标签: sql-server database isolation-level

我已阅读文章(https://www.simple-talk.com/sql/t-sql-programming/questions-about-t-sql-transaction-isolation-levels-you-were-too-shy-to-ask/),我有一个问题根据:

“SERIALIZABLE:当前事务中的查询无法读取尚未提交的另一个事务修改的数据。没有其他事务可以修改当前事务读取的数据直到完成,并且没有其他事务可以插入新行将匹配当前事务中的搜索条件,直到完成为止。因此,Serializable隔离级别可防止脏读,不可重复读和幻像读取。但是,与其他隔离级别相比,它对性能的影响最大。 “

我对于从1个会话/查询中插入不满足搜索条件的新行感到困惑。示例如下:

我们假设我有桌子

EmpID   FirstName
1       john
2       new employee
3       A new employee

并在单独的标签中查询:

--session 1----------------------------------
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

BEGIN TRANSACTION;

    SELECT FirstName FROM EmployeeInfo
    WHERE FirstName like 'new empl%'

    WAITFOR DELAY '00:00:10'  

    SELECT FirstName FROM EmployeeInfo
    WHERE FirstName like 'new empl%'

ROLLBACK TRANSACTION;

---------session 2---------------------------
begin transaction;

    UPDATE EmployeeInfo
    SET FirstName = 'frank'
    WHERE EmpID = 1;

commit transaction;

-----session 3----
insert into EmployeeInfo values('A new employe 2')

我一个接一个地执行查询:会话1,会话2,会话3。 我期望会话1不会停止执行会话2和会话3,因为来自此会话的更新和插入不满足在第一个查询中使用的搜索条件。但是,在结果中,我可以看到会话1必须在会话2和会话3执行之前完成(回滚)。

但是,我在会话1中使用其他搜索条件,如下所示:

--session 1
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

BEGIN TRANSACTION;

SELECT EmpID, FirstName FROM EmployeeInfo
WHERE EmpID = 2

WAITFOR DELAY '00:00:10'  

SELECT FirstName FROM EmployeeInfo

ROLLBACK TRANSACTION;

然后,会话2和会话3独立于会话1完成。 这是为什么?为什么喜欢条件块插入而“=”却没有?

编辑: 1. EmpID上只有一个主键。

1 个答案:

答案 0 :(得分:1)

这是因为"没有其他事务可以插入与当前事务中的搜索条件匹配的新行,直到它完成"。 SQL Server通过采用防止插入冲突的范围锁来强制执行此操作。

如果您在EmployeeInfo.FirstName上有索引,SQL可能可以采用窄锁来强制执行此操作。但是如果没有索引,SQL会锁定一个阻止任何插入的锁。此外,如果SELECT查询谓词不支持索引,它将阻止所有插入。

您可以使用以下方法检查锁的当前状态:

select @@spid this_session, *
from sys.dm_tran_locks

。请注意,这种行为使SERIALIZABLE成为一个不太有用的隔离级别。你应该真的只使用READ COMMITTED和SNAPSHOT,可能会为特定的事务添加锁定提示。