【SQL Server】可重复读隔离级别里的可能死锁
来源:互联网 发布:linux yum安装命令 编辑:程序博客网 时间:2024/06/15 08:52
可重复读隔离级别里的可能死锁
在今天的文章里我想谈论下在可重复读隔离级别(Transaction Isolation Level Repeatable Read)里,当你运行事务时可能引起的2类死锁。当你使用可重复读(Repeatable Read)隔离级别设置你的事务,SQL Server对读取数据把持需要的共享锁(Shared Locks)直到事务的结束(COMMIT或ROLLBAK)。然后当你尝试修改读取的数据(通过UPDATE语句),如果同样的事务多次并发运行,它会英气不同类型的死锁。
循环死锁(Cycle Deadlock)
循环死锁是其中一个最常见的死锁——你就以不同顺序访问资源(例如不同表),最后每个查询等待另一个。使用可重复读隔离级别,但你用多个事务只读写一个表时,也是有可能引起循环死锁。我们来看第1个事务的T-SQL代码:
1 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ 2 GO 3 4 BEGIN TRANSACTION 5 6 SELECT * FROM Person.Person 7 WHERE ModifiedDate = '20030208' 8 9 UPDATE Person.Person10 SET FirstName = '...'11 WHERE ModifiedDate = '20030208'12 13 SELECT * FROM Person.Person14 WHERE ModifiedDate = '20030209'15 16 UPDATE Person.Person17 SET FirstName = '...'18 WHERE ModifiedDate = '20030209'19 20 ROLLBACK21 GO
这是第2个事务的T-SQL代码:
1 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ 2 GO 3 4 BEGIN TRANSACTION 5 6 SELECT * FROM Person.Person 7 WHERE ModifiedDate = '20030209' 8 9 UPDATE Person.Person10 SET FirstName = '...'11 WHERE ModifiedDate = '20030209'12 13 SELECT * FROM Person.Person14 WHERE ModifiedDate = '20030208'15 16 UPDATE Person.Person17 SET FirstName = '...'18 WHERE ModifiedDate = '20030208'19 20 ROLLBACK21 GO
从2个代码可以看到,2个数据范围被读取,最后被更新。如果2个事务在同个时间执行,会发生循环死锁,因为数据范围在不同顺序里被访问。
当SQL Server开始执行UPDATE语句,必须的更新锁(Update Lock(U))不能被获取,因为更新锁(Update Lock)与来自不同会话已授予的共享锁(Shared Lock)不兼容。因为在其它会话共享锁(Shared Lock)已获得,最后2个UPDATE语句会等待——在一个表上就有了经典的循环锁!在这个情况下你必须重写你的代码来让这个特定锁得到解决——以同个顺序访问你的数据范围。
读写/更新死锁(Read/Update Deadlock)
使用可重复读隔离级别的第2类死锁会发生,如果你读取数据,有意向稍后去更新。我们来看1个简单事务的T-SQL代码:
1 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ 2 GO 3 4 BEGIN TRANSACTION 5 6 SELECT * FROM Person.Person 7 WHERE ModifiedDate = '20030208' 8 9 UPDATE Person.Person10 SET FirstName = '...'11 WHERE ModifiedDate = '20030208'12 13 ROLLBACK14 GO
为了引起这类死锁,你只要通过多个会话运行事务。如你从代码里所见,你甚至不需要访问不同数据范围。我们来解释下这里反生了什么。当这个事务在多个会话并发执行时,对读取的数据,所有的会话会获得共享锁。
因为你在可重复读里把持共享受(Shared Lock)直到事务的结束(COMMIT或ROLLBACK),下列UPDATE语句不能获得需要的更新锁(Update Locks),因为它们已被不同会话里获得的共享锁(Shared Locks)所阻塞。死锁!
这里死锁可以通过在SELECT语句里使用提示来提前获取一个更新锁(Update Lock)。
1 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ 2 GO 3 4 BEGIN TRANSACTION 5 6 SELECT * FROM Person.Person WITH (UPDLOCK) 7 WHERE ModifiedDate = '20030208' 8 9 UPDATE Person.Person10 SET FirstName = '...'11 WHERE ModifiedDate = '20030208'12 13 ROLLBACK14 GO
因此在刚开始只有一个SELECT语句能获得必须的更新锁(Update Locks)(更新锁(Update Lock)与本身更新锁(Update Lock)不兼容),继续使用UPDATE语句,最后会释放需要的锁。然后第2个事务会继续它的SELECT和UPDATE语句。
这里你要使用SQL Server内部在更新执行计划里使用的同样的技术:在可重复读隔离级别里,当你读取的数据稍后有意向去更新时,在读取阶段你需要获得一个更新锁来阻止这类死锁。
小结
从这篇文章里可以看到,如果你使用可重复读隔离级别是很容易引起各类死锁。因此当你在这个特定隔离级别里写事务时,你必须要非常小心。
感谢关注!
- 【SQL Server】可重复读隔离级别里的可能死锁
- InnoDB---可重复读隔离级别的实现
- 隔离级别(Isolation Levels)-------可重复读(RR-Repeatable Read)
- MSSQL2008R2 设置事务隔离级别为可重复读时的疑虑与陷阱?
- MySQL使用可重复读作为默认隔离级别的原因
- mysql的可重复读REPEATABLE READ隔离级别和幻读
- MySQL使用可重复读作为默认隔离级别的原因之一
- 数据库事务和隔离级别(重点,不可重复读和可重复度的区别)
- MySQL使用可重复读作为默认隔离级别的原因之一
- MySQL使用可重复读作为默认隔离级别的原因
- SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因
- SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因
- SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因
- MySQL InnoDB事务隔离级别脏读、可重复读、幻读
- 相关隔离 事务隔离级别 脏读 不可重复读 幻读
- sql server 隔离级别
- 事物的隔离级别及产生的影响脏读 不可重复读 幻读
- mysql事务隔离级别以及有问题的读取(脏读,不可重复读,幻象读)
- 用QGIS将shp转json
- Linux 命令-网络操作命令
- 清空KindEditor编辑器内容
- php 冒泡排序
- shell中的kill命令
- 【SQL Server】可重复读隔离级别里的可能死锁
- 【简书如何删除专题?】
- linux编程之进程编程(5)---- 进程管理(task_struct结构体)
- 实例讲解getopt()函数的使用
- 备忘录模式--玩到尽兴须保存,下次开机继续玩(行为模式05)
- 计蒜客-百度的年会游戏(模拟)
- [CSU 1936 无火的余烬] KDTree矩阵内点查询
- Servlet基础
- Linux后台进程管理工具:Supervisor