处理PostgreSQL中的竞争条件

 宝宝贝贝198812126 发布于 2023-01-30 12:34

我有几个工作者,每个工作者都拥有自己与PostgreSQL的连接.工人们操纵着不同的桌子.

工作人员处理来自系统外部的并行请求.正在访问的表之一是用户表.当一些信息出现时,我首先需要确保表中的用户有一条记录.如果没有记录,我希望首先创建一个.

我正在使用以下成语:

if [user does not exist] then [create user]

代码[user does not exist]是:

SELECT id FROM myschema.users WHERE userId='xyz'

我测试是否返回任何行.

(简化)代码[create user]是:

INSERT INTO myschema.users VALUES ('xyz')

当我的系统处理有关同一用户的不同信息的并行流时,我经常会收到PostgreSQL错误:

Key (id)=(xyz) already exists

之所以发生这种情况是因为该SELECT命令不返回任何行,然后另一个工作程序创建用户,任何我的工作程序都尝试执行相同操作,从而导致示例性并发错

根据PostgreSQL文档,默认情况下,每当我隐式启动一个事务时,只要我不提交它,表就会被锁定.我没有使用自动提交,我只在块中提交事务,例如在整个if-else块之后.

实际上,我可以if-else直接将这些东西放入SQL中,但它并不能解决我的锁定问题.我假设"赢家全部使用"范例将起作用,并且设法执行SELECT命令的第一个工作人员将拥有锁,直到它调用COMMIT.

我在SO上已经阅读了很多不同的主题,但我仍然不确定什么是正确的解决方案.我应该使用显式锁定表,因为隐式锁定不起作用?我怎样才能确保只有一个工人拥有一张桌子?

2 个回答
  • 您必须关心事务隔离级别.它应该设置为" SERIALIZABLE".

    原因是Phantom Reads- 事务不会锁定整个表,而只锁定事务已读取的行.

    因此,如果另一个事务插入新数据,它们尚未锁定,则会出现错误.

    Serializable通过阻止所有其他事务来避免这种情况,直到完成此事务.

    你可以通过这样做

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    

    文件:http://www.postgresql.org/docs/9.1/static/transaction-iso.html

    如果您想了解有关此主题的更多信息,我强烈建议您观看此视频:http://www.youtube.com/watch?v = zzz-Xbqp0g0A

    2023-01-30 12:35 回答
  • 实际上,经过ISOLATION LEVEL SERIALIZABLE@maja提出的一些混乱之后,我发现了更简单的机制:

    PERFORM pg_advisory_lock(id);
    ...
    # do something that others must wait for
    ...
    PERFORM pg_advisory_unlock(id);
    

    这里id是一个BIGINT我可以根据我的应用程序的逻辑任意选择值.

    这给了我正在寻找的力量和灵活性.

    2023-01-30 12:37 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有