什么是sql server中的死锁以及什么时候出现?死锁有什么问题以及如何解决?
答案 0 :(得分:26)
通常,死锁意味着两个或多个实体阻止某些源,并且它们都无法完成,因为它们是以循环方式阻塞源。
一个例子:假设我有表A和表B,我需要在A中进行一些更新然后B我决定在使用时锁定它们(这是非常愚蠢的行为,但它服务于它目的)。在同一时刻,其他人以相反的顺序做同样的事情 - 首先锁定B,然后锁定A.
按时间顺序,会发生这种情况:
proc1:锁定A. proc2:锁定B
proc1:锁定B - 开始等待,直到proc2释放B proc2:锁定A - 开始等待,直到proc1释放A
很明显,他们都没有完成。那是僵局。洞越来越深,但这只是一个入口,如果你需要了解更多,那就投入时间吧。在我们的大学里有关于这一点的全部讲座 - 所以不要认为阅读一些文章会让你成为专家; - )
答案 1 :(得分:8)
当两个人需要多个资源来执行时,以及每个人锁定某些资源的情况下会发生死锁。这导致A不能在没有B的情况下执行,反之亦然。
假设我有人A和人B.他们都需要运行两行(Row1和Row2)。
Person A无法运行,因为它需要Row2,Person B因为需要Row1而无法运行。这两个人都无法执行,因为他们锁定了对方需要的东西,反之亦然。
减少死锁的一种相当简单的方法是在所有复杂的事务中,您应该以相同的顺序执行操作。换句话说,以相同的顺序访问Table1然后Table2。这将有助于减少发生的死锁数量。
答案 2 :(得分:3)
正如我在this article中所解释的那样,当两个并发事务无法进行时会发生死锁,因为每个事务都等待另一个释放锁,如下图所示。
因为两个事务都处于锁获取阶段,所以两个都不会在获取下一个之前释放锁。
如果您使用的是依赖于锁的并发控制算法,则始终存在在死锁情况下运行的风险。死锁可能发生在任何并发环境中,而不仅仅是数据库系统中。
例如,如果两个或多个线程正在等待先前获取的锁,则多线程程序可能会死锁,从而使任何线程都无法取得任何进展。如果在Java应用程序中发生这种情况,则JVM不能仅强制Thread停止其执行并释放其锁。
即使Thread
类公开了stop
方法,该方法自Java 1.1以来也已被弃用,因为它可能导致对象在线程停止后处于不一致状态。相反,Java定义了interrupt
方法,该方法作为提示,因为被中断的线程可以简单地忽略该中断并继续执行。
因此,Java应用程序无法从死锁情况中恢复,应用程序开发人员有责任以永远不会发生死锁的方式对锁获取请求进行排序。
但是,数据库系统无法强制执行给定的锁获取顺序,因为无法预见某个事务将要进一步获取哪些其他锁。保留锁定顺序成为数据访问层的责任,数据库只能帮助从死锁情况中恢复。
数据库引擎运行一个单独的进程,该进程扫描当前冲突图以查找锁定等待周期(由死锁引起)。 当检测到周期时,数据库引擎将选择一个事务并将其中止,从而释放其锁,以便其他事务可以取得进展。
与JVM不同,数据库事务被设计为基本的工作单元。因此,回滚会使数据库保持一致状态。
虽然数据库选择回滚被阻塞的两个事务之一,但并不总是能够预测哪个回滚。根据经验,数据库可以选择以较低的回滚成本回滚事务。
根据Oracle documentation,检测到回滚的事务是其语句将被回滚的事务。
SQL Server允许您通过DEADLOCK_PRIORITY
会话变量控制在死锁情况下哪个事务更可能回滚。
DEADLOCK_PRIORITY
会话可以接受-10到10之间的任何整数,也可以接受诸如LOW (-5)
,NORMAL (0)
或HIGH (5)
之类的预定义值。
在发生死锁的情况下,当前事务将回滚,除非其他事务的死锁优先级值较低。如果两个事务具有相同的优先级值,则SQL Server将以最小的回滚成本回滚该事务。
如documentation中所述,PostgreSQL不保证要回滚哪个事务。
MySQL尝试使用roll back the transaction that modified the leats number of records,因为释放更少的锁的成本更低。
有关此主题的更多详细信息,请同时查看this article。
答案 3 :(得分:1)
每次交易两次(或多次)时可能导致的僵局 等待另一个持有的锁被释放。