本文介绍了SQL语句是否确保postgres中的原子性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我的程序中有一个使用多用户支持的简单错误。我正在使用knex
构建SQL查询,并且我有一个描述场景的伪代码:
const value = queryBuilder().readDataFromTheDatabase();//executes this
//do some other work and get value
queryBuilder.writeValueToTheDatabase(updateValue(value));
这段代码用于某种中间件功能。如您所见,这可能是争用条件,即当多个用户访问该事物时,其中一个用户尝试在大致相同的时间内执行此操作时,会得到陈旧的值。
我的解决方案
因此,我认为可能解决方案是创建一条queryBuilder语句:
queryBuilder().readAndUpdateValueInTheDatabase();
因此,我可能不得不使用一点plpgsql
。我想知道这个解决方案是否足够。该语句是否会自动执行?即,当一个请求读取但未完成写入时,另一个请求是等待读取和写入,还是只等待写入但读取过时的值?推荐答案
若要避免此类设置出现争用情况,必须在同一数据库事务中同时运行读取和写入。
有两种方法:
使用默认
READ COMMITTED
隔离级别,并在读取行时锁定它们:SELECT ... FROM ... FOR NO KEY UPDATE;
这会锁定行以防止并发修改,并且锁定将一直保持到事务结束。
使用
REPEATABLE READ
隔离级别,不要锁定任何内容。如果有人并发地修改了该行,UPDATE
将收到序列化错误(SQLSTATE 40001)。在这种情况下,您可以回滚事务,然后在新的REPEATABLE READ
事务中重试。
如果您预计冲突频繁,则第一个解决方案通常更好,如果冲突很少发生,则第二个解决方案更好。
请注意,在这两种情况下,您都应该使数据库事务尽可能短,以保持较低的冲突风险。
这篇关于SQL语句是否确保postgres中的原子性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!