メモ:存在しない行を HOLDLOCK すると、Range でロックする

たまたま試す機会があったのでメモ。

テーブル ヒント (Transact-SQL) - SQL Server | Microsoft Docs
には HOLDLOCK は SERIALIZABLE 相当と書かれていて、
SERIALIZABLE では、

SERIALIZABLE 分離レベルで実行しているトランザクションと同じセマンティクスで、スキャンが実行されます。

となっているので、ドキュメント通りなんだけど試したから書いとく。

例1:
存在しない行に UPDLOCK を掛けても、ロックは取られない。
なので、他のトランザクションで行を追加されてしまう。

ロック掛けるセッション

begin tran

select * from [Table] (UPDLOCK) where Id = 6

f:id:odashinsuke:20190118135407j:plain
追加するセッション

begin tran
insert into [Table] values (6, 'abcabc')
select * from [Table]
rollback

f:id:odashinsuke:20190118135431j:plain
Id = 6 が追加される。

例2:
HOLDLOCK にすると、行を追加されない。

ロック掛けるセッション

begin tran

select * from [Table] (HOLDLOCK) where Id = 6

f:id:odashinsuke:20190118140337j:plain 追加するセッション

begin tran
insert into [Table] values (6, 'abcabc')
select * from [Table]
rollback

f:id:odashinsuke:20190118140401j:plain
ロックが解放されるまで追加できない。

ロック状況 f:id:odashinsuke:20190118140438j:plain

範囲でロックを取っているので、今回の場合は Id = 6 だけではなく、6 以上の値では insert 出来ない。
逆に Id = 0 や -1 は insert 可能。

Id が 1 と 5 のデータしかない場合に、Id = 3 で HOLDLOCK 掛けたら、1 より小さい値や、5 より大きい値はロックの範囲外。
2, 3, 4 はロックの範囲内。
多分こんな認識で大丈夫のはず。