假设我在可串行化事务中有这样的代码:
users = "select * from users where account='x'"
for (u of users) {
if (condition)
"UPDATE users SET foo = 'bar' where id=u.id"
}
Run Code Online (Sandbox Code Playgroud)
我需要使用SELECT FOR UPDATE代替吗SELECT?
如果是,那么上面的可序列化隔离有什么意义呢?根据可序列化隔离,当前代码应该可以正常工作。
如果不是,那还有什么意义呢SELECT FOR UPDATE?它只对较低的隔离水平有用吗?
从功能上看,没有什么区别;该SERIALIZABLE级别保证交易内部和外部一致;然而,从操作的角度来看,有一个区别:该FOR UPDATE子句立即锁定任何并发可序列化事务的行(并等待任何先前的锁定(如果有))。如果没有它,它就不会(现在大多数数据库包括pg都使用快照读取来满足可重复读取),但是在不可序列化并发(总是在写入时)的情况下,其中一个事务将被回滚,并且需要重试了。
那么有何不同呢?好吧,我们假设您的事务需要 10 分钟才能完成,但您事先知道哪些行将被更新。提前锁定它们将使 10 分钟的事务在开始之前等待任何锁定,从而消除了 5 分钟后回滚的风险。然后,它将锁定影响相同行的任何并发事务,直到完成为止,而不是可能回滚这些事务。
因此,通过明智地使用立即锁定语义,可以减少并发失败/回滚的数量。另一方面,不加区别地使用立即锁定语义(即在不受影响的行上)可能会杀死并发性。
总而言之,仅在SERIALIZABLE模式上:功能相同、操作不同、明智地使用可能是好的,如果有疑问就根本不使用。
对于较低的隔离级别,FOR UPDATE在功能上是相关的,因为它允许即快照并发通过显式锁定方向实现可串行性。
| 归档时间: |
|
| 查看次数: |
448 次 |
| 最近记录: |