在“最小化死锁”的 MS Technet 页面上,它说“无法完全避免死锁”。更具体地说,它指出
如果所有并发事务以相同的顺序访问对象,死锁就不太可能发生。
这意味着理论上可能会发生死锁,即使所有事务都以相同的顺序访问对象。有人可以举一个例子说明这怎么可能吗?
在“最小化死锁”的 MS Technet 页面上,它说“无法完全避免死锁”。更具体地说,它指出
如果所有并发事务以相同的顺序访问对象,死锁就不太可能发生。
这意味着理论上可能会发生死锁,即使所有事务都以相同的顺序访问对象。有人可以举一个例子说明这怎么可能吗?
只是为了提供一个简单的代码示例来进一步查尔斯的回答
CREATE TABLE T(X INT)
然后在两个并发连接中运行
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
SELECT * FROM T
WAITFOR DELAY '00:00:10'
INSERT INTO T VALUES(1)
COMMIT
僵局。
问题是两个连接都可以获取资源上的共享锁,但是当它们需要将其转换为独占锁时会相互阻塞。
一种方法是在使用隔离级别可序列化时。
如果您有父子关系,例如在具有客户、客户帐户以及这些帐户的个人财务借方和贷方的会计数据库中,则:
您有一个数据库事务,其中包含子表中的多个平衡借方和贷方条目,以及客户表中帐户余额的伴随更新。
在可序列化的隔离级别,为了防止所谓的幻读,数据库引擎对 SQL 语句必须读取的所有记录(在本例中为贷记表和借记表)设置范围锁。这确保了在此 Tx 计算新的客户余额时,没有其他交易可以将新的贷方或借方插入表中。任何插入新贷方或借方的尝试都会被锁阻止。
同时,第一个 Tx 也被阻塞,因为另一个插入 Tx 将锁定 Customer Table 行,因为它还需要更新客户余额。在提交整个 Tx 之前,锁不会释放,因此两个事务都相互阻塞......死锁。