交易和锁

Sha*_*rkz 3 c# transactions sql-server-2008 locks

我目前正在处理交易并感到困惑。这些事务是在数据访问层创建的,而不是在数据库(SQL Server 2008)的存储过程中创建的。我了解为事务设置的隔离级别的正常工作。我无法理解以下场景中会发生什么。

  1. 发起交易
  2. 选择 ID=1 的员工。
  3. 更新员工 ID=1。
  4. 犯罪

有多个线程在做同样的事情,但 ID 不同。但可能存在两个线程查找相同 ID 的情况。我们将它们称为线程 A 和 B。对于这两个线程,上述步骤按以下方式进行。隔离级别设置为可重复读取。

A1。发起交易A2。选择 ID=1 的员工。B1。发起交易B2。选择 ID=1 的员工。A3。更新员工 ID=1。A4。提交 B3。更新员工 ID=1。B4。犯罪

我真正想从事务中实现的是,当线程 A 选择特定记录时,线程 B 甚至不应该能够选择该记录。我不知道在这种情况下使用事务和锁是否走在正确的轨道上。

等待回复:)

Pol*_*fun 5

您应该使用 UPDLOCK 表提示来防止死锁,例如,

select * from employee with (updlock) where id = @id
update employee set name = @name where id = @id
Run Code Online (Sandbox Code Playgroud)

如果没有这个,你可能会遇到死锁,因为 select 默认情况下采用共享读锁:

  1. 事务 A 执行选择(共享读锁)。
  2. 事务 B 执行选择(共享读锁,可能位于与事务 A 相同的某些记录上,例如,如果采用了页锁)。
  3. 事务 A 现在执行更新,这需要独占写锁(锁升级),但必须等待事务 B 释放其共享读锁。
  4. 事务 B 现在也想要进行更新,但必须等待事务 A 释放其共享读锁。

所以事务 A 和 B 现在正在互相等待 - 经典的锁升级死锁。UPDLOCK 表提示避免了这种情况,因为它强制 select 采取独占锁:

  1. 事务A执行选择(排它更新锁)。
  2. 事务 B 想要执行其 select,但必须等待事务 A 首先释放其锁。
  3. 事务 A 现在执行更新并提交,释放选择所占用的更新锁。
  4. 事务 B 现在可以进行选择。

编辑:您可以将 UPDLOCK 与 ROWLOCK 结合起来请求行级锁定,例如“with (updlock, rowlock)”。您可以询问,但可能并不总能得到它 - 请参阅http://msdn.microsoft.com/en-us/library/ms187373(v=sql.100).aspx。此外,行锁可能比页锁更昂贵,因为如果使用行锁,SQL Server 可能会需要跟踪更多的锁。所以我会让SQL Server自己选择锁的范围,它通常做得很好;在这种情况下,它不应该采用表锁。仅在没有行锁时出现问题时才显式使用行锁。

另请注意,行锁本身并不能防止两个事务选择同一记录(行)然后尝试更新它的死锁 - 因此您始终需要为此使用 updlock。