繁体   English   中英

如何在PostgreSQL中同时运行多个非原子计算的多个客户端中防止更新异常?

[英]How to prevent update anomalies with multiple clients running non-atomic computations concurrently in PostgreSQL?

我正在使用复制(三个主服务器,两个从属服务器)访问三个PostgreSQL实例:

  • 第一台(未公开的)服务器基本上遍历特定表中的每一行,并为每个用户每个滴答(基于那些资源的生产率)连续更新特定的列(资源)。
  • 第二台服务器是一个公开的API,它公开了各种功能,例如花费一定数量的那些资源。

为了访问和处理数据,我使用一个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吗? 这样就足够了吗?

您的问题尚不清楚,但是如果您的事务跨越多个语句,但需要具有一致的数据库状态,则基本上有两个选择:

  1. 使用悲观锁定:从数据库读取值时,请使用SELECT ... FOR UPDATE 然后,在事务期间将锁定行,并且没有并行事务可以修改它们。

  2. 使用开放式锁定:以REPEATABLE READ隔离级别启动您的事务。 然后,您会在整个事务期间看到数据库的一致快照。 如果其他人在您读取数据后修改了您的数据,则UPDATE将导致序列化错误 ,您将不得不重试该事务。

如果冲突很少发生,乐观锁定会更好,而如果可能发生冲突,则悲观锁定会更好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM