SQL 服务器:Tablock,在 select 之前或之后锁定?

SQL Server : Tablock, locks before or after select?

在下面的示例中,当使用 with (tablockx) 时,锁定是在 select 确定最大值之前完成的,还是之后完成的?是否存在插入语句插入 table "table1" 的竞争条件,或者是否保证 @foo 将包含在 table 中找到的最大值,直到事务被提交或回滚?

begin Transaction

declare @foo int = (select max(col1) from table1 with (tablockx))
-- Is it possible that max(col1) can be > @foo here?

Commit Transaction

如果重要的话,我正在使用 SQL Server 2008 R2

Is the locking done before the select determines the max value, or after

之前,在查询优化器执行之前。事后再做也于事无补。这是您正在执行的语句的锁定方法。

Is there a race condition with insert statements inserting into table "table1"

不,因为您使用的是 TABLOCKX 而不仅仅是 TABLOCK。后者允许共享锁,但您通过 TABLOCKX.

获得 table 上的独占锁

Is it guaranteed that @foo will contain the max value found in the table until the transaction is committed or rolled back

是的,所有其他事务都将被阻止(删除、插入、更新等)

正在测试

要对此进行测试,请创建一个 table 并插入一个值

create table t1_delete (col1 int)
insert into t1_delete
values (1)
go

接下来,在一个 SSMS 面板中 运行 您的代码,但注释掉 COMMIT TRAN

begin Transaction

declare @foo int = (select max(col1) from t1_delete with (tablockx))
-- Is it possible that max(col1) can be > @foo here?
select @foo
--Commit Transaction

现在,在 新的 SSMS window 中尝试插入一个新值,或者其他任何东西

insert into t1_delete
values(2)

您会注意到查询旋转。如果您在 另一个查询 window 中从 Adam Mechanic 运行 exec sp_whoIsActive,您可以明白为什么。具体来说,检查插入会话的 blocking_session_id。这将是与 sql_test 的会话,例如 begin transaction declare @foo....

测试完别忘了提交事务

Tablockx 将获取一个独占锁,该锁在事务提交或回滚时释放。所以你的评论区会被屏蔽