本文介绍了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。我想知道这个解决方案是否足够。该语句是否会自动执行?即,当一个请求读取但未完成写入时,另一个请求是等待读取和写入,还是只等待写入但读取过时的值?

推荐答案

若要避免此类设置出现争用情况,必须在同一数据库事务中同时运行读取和写入。

有两种方法:

  1. 使用默认READ COMMITTED隔离级别,并在读取行时锁定它们:

    SELECT ... FROM ... FOR NO KEY UPDATE;
    

    这会锁定行以防止并发修改,并且锁定将一直保持到事务结束。

  2. 使用REPEATABLE READ隔离级别,不要锁定任何内容。如果有人并发地修改了该行,UPDATE将收到序列化错误(SQLSTATE 40001)。在这种情况下,您可以回滚事务,然后在新的REPEATABLE READ事务中重试。

如果您预计冲突频繁,则第一个解决方案通常更好,如果冲突很少发生,则第二个解决方案更好。

请注意,在这两种情况下,您都应该使数据库事务尽可能短,以保持较低的冲突风险。

这篇关于SQL语句是否确保postgres中的原子性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-02 03:27