【SqlServer|sql server的UPDLOCK、HOLDLOCK试验】
文章图片
-- 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 死锁监视器会定期检查 陷入死锁的任务,检测到了循环依赖关系,选择其中一个任务作为牺牲品,终止并提示错误
文章图片
再举一个具体的例子详细说明:
-- 事务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 TRANROLLBACK TRAN
BEGIN TRAN
SELECT * FROM content_article with (HOLDLOCK) where id = '1000002';
UPDATE content_article SET weighted = 2 where id = '1000001';
COMMIT TRAN
推荐阅读
- Java|Java基础——数组
- 人工智能|干货!人体姿态估计与运动预测
- java简介|Java是什么(Java能用来干什么?)
- Java|规范的打印日志
- Linux|109 个实用 shell 脚本
- 数据库|SQL行转列方式优化查询性能实践
- 程序员|【高级Java架构师系统学习】毕业一年萌新的Java大厂面经,最新整理
- Spring注解驱动第十讲--@Autowired使用
- mysql|一文深入理解mysql
- 达梦数据库|DM8表空间备份恢复