什么是SQL Server中的死锁,它是何时出现的?
死锁可能存在哪些问题以及如何解决呢?
什么是SQL Server中的死锁,它是何时出现的?
死锁可能存在哪些问题以及如何解决呢?
通常,死锁是指两个或多个实体阻塞了某些资源,并且它们都无法完成,因为它们以循环方式阻塞资源。
举个例子:假设我有表A和表B,我需要先在A中进行一些更新,然后在B中进行更新,并决定在使用时同时锁定它们(这是非常愚蠢的行为,但现在它能够说明问题)。与此同时,另一个人以相反的顺序做了同样的事情 - 首先锁定了B,然后锁定了A。
按时间顺序发生的事情如下:
proc1: 锁定 A
proc2: 锁定 B
proc1: 锁定 B - 开始等待,直到proc2释放B
proc2: 锁定 A - 开始等待,直到proc1释放A
他们中没有一个会完成。这就是死锁。在实践中,这通常会导致超时错误,因为不希望任何查询永远挂起,并且底层系统(例如数据库)将终止未能及时完成的查询。
死锁的一个真实例子是当你把房门钥匙锁在车里,而把车钥匙锁在房子里时。
死锁发生在两个并发事务互相等待对方释放锁的情况下,如下图所示。
由于两个事务都处于锁获取阶段,因此在获取下一个锁之前,它们都不会释放任何锁。
如果您使用依赖于锁的并发控制算法,则始终存在运行进入死锁状态的风险。死锁可以在任何并发环境中发生,而不仅仅是在数据库系统中。
例如,如果两个或多个线程正在等待先前获取的锁,以至于没有线程可以取得任何进展,则多线程程序可能会死锁。如果这在Java应用程序中发生,则JVM不能强制一个线程停止执行并释放其锁。
即使Thread
类公开了 stop
方法,但此方法自Java 1.1版本以来已被弃用,因为它可能会导致线程停止后对象处于不一致状态。相反,Java定义了一个interrupt
方法,作为线程的提示,被中断的线程可以简单地忽略中断并继续执行。与JVM不同,数据库事务被设计为原子工作单元。因此,回滚会使数据库处于一致状态。
当数据库选择回滚其中一个被卡住的事务时,并不总是能够预测哪一个事务将被回滚。通常情况下,数据库可能会选择回滚回滚成本较低的事务。
根据Oracle文档所述,检测到死锁的事务将会被回滚。
SQL Server允许您通过DEADLOCK_PRIORITY
会话变量控制在死锁情况下哪个事务更有可能被回滚。
DEADLOCK_PRIORITY
会话可以接受从-10到10的任何整数或预定义值,例如LOW(-5)
、NORMAL(0)
或HIGH(5)
。
在死锁情况下,当前事务将回滚,除非其他事务具有更低的死锁优先级值。如果两个事务具有相同的优先级值,则SQL Server将回滚回滚成本较小的事务。