我目前正在处理事务并且感到困惑。这些事务是在数据访问层创建的,而不是在数据库的存储过程中创建的 (SQL Server 2008)。 我了解为事务设置的隔离级别的正常工作。 我无法理解在以下情况下会发生什么。
- 发起交易
- 选择 ID=1 的员工。
- 更新 ID=1 的员工。
- promise
有多个线程在做同样的事情但 ID 不同。但是可能会出现这样的情况,即在两个线程中查找相同的 ID。让我们称它们为线程 A 和 B。以上步骤针对这两个线程按以下方式进行。隔离级别设置为可重复读取。
A1。发起交易 A2。选择 ID=1 的员工。 B1.发起交易 B2.选择 ID=1 的员工。 A3.更新 ID=1 的员工。 A4.犯罪 B3.更新 ID=1 的员工。 B4.提交
我真正想从事务中实现的是,当线程 A 选择特定记录时,线程 B 甚至不能选择该记录。对于这种情况,我不知道通过使用事务和锁来思考是否在正确的轨道上。
等待回复:)
请您参考如下方法:
您应该使用 UPDLOCK 表提示来防止死锁,例如,
select * from employee with (updlock) where id = @id
update employee set name = @name where id = @id
没有这个你可能会遇到死锁,因为默认情况下选择采用共享读锁:
- 事务 A 执行选择(共享读锁)。
- 事务 B 执行选择(共享读锁,可能在某些 与事务 A 相同的记录,例如,如果页面锁定被占用)。
- 事务 A 现在执行更新,这需要独占写入 lock(锁升级),但要等待事务B释放 它的共享读锁。
- 事务 B 现在也想进行更新,但必须等待 事务 A 释放其共享读锁。
因此事务 A 和 B 现在正在等待对方 - 经典锁升级死锁。 UPDLOCK 表提示避免了这种情况,因为它强制选择采用排他锁:
- 事务 A 进行选择(独占更新锁)。
- 事务 B 想要进行选择,但必须先等待事务 A 释放其锁。
- 事务 A 现在执行更新并提交,释放 select 获取的更新锁。
- 事务 B 现在可以进行选择。
编辑:您可以将 UPDLOCK 与 ROWLOCK 结合使用以请求行级锁,例如“with (updlock, rowlock)”。你可以问,但你不一定总能得到 - 见http://msdn.microsoft.com/en-us/library/ms187373(v=sql.100).aspx .此外,行锁可能比页锁更昂贵,因为如果使用行锁,SQL Server 可能需要跟踪更多的锁。所以我会让 SQL Server 自己选择锁的范围,它通常做得很好;在这种情况下,它不应该使用表锁。仅在没有行锁的情况下出现问题时才显式使用行锁。
另请注意,行锁本身不会阻止两个事务选择相同记录(行)然后尝试更新它的死锁 - 因此您始终需要一个更新锁。
