我正在使用复制(三个主服务器,两个从属服务器)运行三个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吗?这样就够了吗?
答案 0 :(得分:1)
您的问题尚不清楚,但是如果您的事务跨越多个语句,但需要具有一致的数据库状态,则基本上有两个选择:
使用悲观锁定:从数据库中读取值时,请使用SELECT ... FOR UPDATE
。然后,在事务期间将锁定行,并且没有任何并发事务可以修改它们。
使用开放式锁定:以REPEATABLE READ
隔离级别启动事务。然后,您会在整个事务期间看到数据库的一致快照。如果其他人在您读取数据后修改了您的数据,则您的UPDATE
将导致序列化错误,您将不得不重试该事务。
如果冲突很少发生,乐观锁定会更好,而如果可能发生冲突,则悲观锁定会更好。