【问题标题】:Resolve write after read race condition解决读后写竞争条件
【发布时间】:2021-03-04 02:17:39
【问题描述】:

这是一个我需要帮助的竞争条件场景:

我们正在尝试在数据库中创建项目 A 和项目 B,并且我们希望将项目 B 保持为“childOf”项目 A。假设创建项目 B 的请求以及“childOf”关系数据在之前到达请求创建项目 A。

以下是假设单个作业一次处理这些请求的步骤

  • 创建项目 B 的请求首先到达“childOf”关系数据,表明项目 B 是项目 A 的子项
  • 首先,我们检查项目 A 是否存在
  • 如果项目 A 存在,则创建项目 B,并在项目 B 和项目 A 之间创建“childOf”关系记录
  • 如果项目 A 不存在,该过程会在数据库中创建一条待处理记录,说明项目 A 尚未创建
  • 当创建项目 A 的请求到达时,项目 A 被创建,数据库检查与作为父项目 A 关联的任何“待处理”记录,如果有待处理记录,则在项目之间添加“childOf”关系B 和项目 A 现在项目 A 已在数据库中创建。

如果有多个作业同时运行,可能会出现以下竞争情况:

Process A Process B
req to create item B
check db for item A and item A is not found
req to create item A arrives and item A is created
since item A doesn't exist when it was checked last time, create a pending record in db with the relationship details
the pending record stays in the DB forever since item A is already created by process A while the pending record hasn't been inserted in the DB yet

如何解决这种竞争条件?对不起,如果这太抽象了。让我知道我是否应该进一步详细说明。

【问题讨论】:

    标签: database postgresql concurrency race-condition


    【解决方案1】:

    我会创建一个“待处理”对象,而不是作为一个单独的、不同的对象,而是在一个“真实”对象所在的位置,只是用一个标志来指示它的状态。

    CREATE TABLE object (
       name varchar(100)
          CONSTRAINT object_pkey PRIMATY KEY,
       pending boolean DEFAULT FALSE NOT NULL
    );
    

    现在我要添加一个像这样的常规对象:

    INSERT INTO object (name)
    VALUES ('A')
    ON CONFLICT ON CONSTRAINT object_pkey
    DO UPDATE SET pending = FALSE;
    

    一个挂起的对象是这样插入的:

    INSERT INTO onject (name, pending)
    VALUES ('A', TRUE)
    ON CONFLICT ON CONSTRAINT object_pkey
    DO NOTHING;
    

    然后你不需要在添加对象之前检查是否存在,竞争条件就消失了。 INSERT ... ON CONFLICT 被设计成原子性的并且没有竞争条件。

    【讨论】:

    • 不知道 postgres 有一个原子“upsert”操作。非常酷,这回答了我的问题,tysm!
    猜你喜欢
    • 2016-07-22
    • 2017-03-20
    • 2019-08-20
    • 2012-04-17
    • 2015-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多