[英]How to prevent update anomalies with multiple clients running non-atomic computations concurrently in PostgreSQL?
我正在使用复制(三个主服务器,两个从属服务器)访问三个PostgreSQL实例:
为了访问和处理数据,我使用一个ORM库,该库允许我编写如下代码:
const resources = await repository.findById(1337);
// some complex computation
resources.iron = computeNewIron(resources.iron);
await repository.save(resources);
当然,当处理价格变动的服务器尝试更新资源量时,API可能会想扣除一定数量的资源,这可能会导致其中任一服务器承担一定数量的不正确资源,基本上您的典型UPDATE异常。
我的问题是,我不仅在编写“简单”原子查询,例如UPDATE table SET iron = iron + 42 WHERE id = :id
。 ORM库在内部使用的是直接分配,该分配不会自引用各个列,这会产生类似于UPDATE table SET iron = 123 WHERE id = :id
,其中该数量是先前计算得出的。
我可以假设,如果我使用人工编写的查询来自动地使用自引用对值进行递增/递减,则可以防止上述异常。 我想知道哪些其他选项可以缓解此问题。 我应该在事务中包装SELECT / COMPUTE / UPDATE吗? 这样就足够了吗?
您的问题尚不清楚,但是如果您的事务跨越多个语句,但需要具有一致的数据库状态,则基本上有两个选择:
使用悲观锁定:从数据库读取值时,请使用SELECT ... FOR UPDATE
。 然后,在事务期间将锁定行,并且没有并行事务可以修改它们。
使用开放式锁定:以REPEATABLE READ
隔离级别启动您的事务。 然后,您会在整个事务期间看到数据库的一致快照。 如果其他人在您读取数据后修改了您的数据,则UPDATE
将导致序列化错误 ,您将不得不重试该事务。
如果冲突很少发生,乐观锁定会更好,而如果可能发生冲突,则悲观锁定会更好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.