SQL Server : Tablock, locks before or after select?

Viewed 1258

In the following example, when using with (tablockx) 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", or is it guaranteed that @foo will contain the max value found in the table until the transaction is committed or rolled back?

begin Transaction

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

Commit Transaction

If it matters, I'm using SQL Server 2008 R2

2 Answers

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

Before, by the query optimizer before it is executed. It wouldn't help to do it after, after all. This is the locking method for statement you are executing.

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

No, since you are using TABLOCKX and not just TABLOCK. The latter allows shared locks, but you are getting an exclusive lock on the table via TABLOCKX.

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

Yup, all other transactions will be blocked (deletes, inserts, updates, etc)

TESTING

To test this, create a table an insert a value

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

Next, in one SSMS panel run your code but comment out the 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

Now, in a new SSMS window try to insert a new value, or whatever

insert into t1_delete
values(2)

You will notice the query spins. You can see why if you run exec sp_whoIsActive from Adam Mechanic in another query window. Specifically, check out the blocking_session_id for your insert session. It will be the session with sql_test like begin transaction declare @foo....

Don't forget to commit the transaction after the test

Tablockx will grab an exclusive lock that is released when the transaction is committed or rolled back. So your comment area would be blocked.

Related