我正在学习 SQL Server 并试图了解 SQL Server 如何更新一行。
据我了解,首先 SQL Server在数据库上放置一个意图排他锁,然后在表上放置一个意图排他锁,然后在要更新的记录上放置一个更新锁。稍后,它会将行上的更新锁转换为排他锁,以便修改行中的数据。
但问题是共享锁与更新锁兼容。因此,虽然该行上有一个更新锁,但其他会话仍然可以使用共享锁读取该行。使用行上的共享锁,不可能将更新锁转换为排他锁,因为共享锁和排他锁不兼容。
这是否意味着如果有会话连续读取该行,SQL Server 根本没有机会更新该行。这可能会持续很长时间。这是真的?SQL Server 会等到行上没有共享锁后才开始更新其中的数据吗?
“连续”是指一个会话读取该行,并且在从该行释放共享锁之前,另一个会话在同一行上放置一个共享锁。在第二个共享锁从行中释放之前,另一个会话在同一行上放置另一个共享锁,依此类推。因此,基本上,该行上总是至少有一个共享锁。
在您描述的情况下,SQL Server 不会对数据库进行意向排他 (IX) 锁定。IX 锁是在对象(表)级别以及在包含目标行的页面上获取的,然后再对行获取更新 (U) 锁。
新到达的重复共享 (S) 锁会阻止从更新 (U) 锁转换为独占 (X) 锁的情况称为“锁饥饿”。SQL Server 采取措施避免这种情况。
在 SQL Server 的早期版本中,锁是按照严格的先进先出 (FIFO) 顺序授予的。这意味着等待锁总是在队列的前面取得进展。
从那时起,这种安排已经多次细化,并不是所有的细节都是公开的。如果您有兴趣,可以在 Microsoft CSS 团队的SQL Server、锁管理器和“宽松的”FIFO中找到一些详细信息。一个简短的报价: