sql server的UPDLOCK、HOLDLOCK试验

sql server的UPDLOCK、HOLDLOCK试验_第1张图片

-- 2个tran都查询id = 1000001数据,然后尝试更新
-- 结果2边都能在10s内结束
BEGIN TRAN
SELECT * FROM content_article where id = '1000001';
WAITFOR DELAY '00:00:10'
UPDATE content_article SET weighted = 2 where id = '1000001';
COMMIT TRAN

-- 查询时都加上HOLDLOCK, 左边先运行
-- 结果:左边18s结束,右边12s结束
-- 右边报错:事务(进程 ID 58)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品。请重新运行该事务。
BEGIN TRAN
SELECT * FROM content_article with (HOLDLOCK) where id = '1000001';
WAITFOR DELAY '00:00:10'
UPDATE content_article SET weighted = 2 where id = '1000001';
COMMIT TRAN

-- 左边不变,右边加上UPDLOCK
-- 结果:同上-----------应该说明右边并没有活动UPDLOCK吧
BEGIN TRAN
SELECT * FROM content_article with (HOLDLOCK) where id = '1000001';
WAITFOR DELAY '00:00:10'
UPDATE content_article SET weighted = 2 where id = '1000001';
SELECT * FROM op_content_article where id = '1000001';
COMMIT TRAN

推测:
1.因为数据库默认 隔离级别 读已提交,故select语句只是S锁,不加HOLDLOCK,二边事务正常运行;
2.加了HOLDLOCK,首次select的语句会获得UPDLOCK, 故发生死锁时,未获得UPDLOCK报错了,即右边后面2次都无法获得UPDLOCK

实际:如官方文档所示,sql server 死锁监视器会定期检查 陷入死锁的任务,检测到了循环依赖关系,选择其中一个任务作为牺牲品,终止并提示错误
sql server的UPDLOCK、HOLDLOCK试验_第2张图片
再举一个具体的例子详细说明:

-- 事务1先获得row1共享锁
-- 事务2获得row2共享锁
-- 事务2尝试获得row1排他锁---但事务1的共享锁阻止了
-- 事务1尝试获得row2排他锁---但事务2的共享锁阻止了

-- 事务1和事务2互相死锁,被死锁监视器检测到,故10s左右 两边都会执行完毕;
BEGIN TRAN
SELECT * FROM content_article (HOLDLOCK) where id = '1000001';
WAITFOR DELAY '00:00:10'
UPDATE content_article SET weighted = 2 where id = '1000002';
COMMIT TRAN

ROLLBACK TRAN
BEGIN TRAN
SELECT * FROM content_article with (HOLDLOCK) where id = '1000002';
UPDATE content_article SET weighted = 2 where id = '1000001';
COMMIT TRAN

你可能感兴趣的:(SqlServer,sql,java,数据库,sqlserver)