如何区分 Postgres 存储函数中 FOUND 何时为 false 以及行版本何时过时

问题描述 投票:0回答:1

在 Postgres 支持的 .NET 应用程序中实现乐观并发时,我陷入了僵局。

以下存储函数返回 FOUND,如果传递的 ID 与 WHERE 子句不匹配,则调用端点将返回 404:

CREATE OR REPLACE FUNCTION institution_delete_by_id(IN in_id UUID) RETURNS BOOLEAN
    LANGUAGE plpgsql
AS
$$
BEGIN
    DELETE
    FROM institution
    WHERE id = in_id;
    RETURN FOUND;
END
$$;

引入乐观并发,我会做类似以下的事情(我想当我读完之后我会使用 xmin ):

CREATE OR REPLACE FUNCTION institution_delete_by_id(IN in_id UUID, IN in_version BIGINT) RETURNS BOOLEAN
    LANGUAGE plpgsql
AS
$$
BEGIN
    DELETE
    FROM institution
    WHERE id = in_id AND version = in_version; -- Here's the addition
    RETURN FOUND;
END
$$;

但是,这样做时,应用程序无法推断 FOUND 是否因 ID 不匹配而为假,或者 FOUND 是否因表的并发更新而为假。因此,端点无法判断是否应该返回 404 还是 409(冲突)。

那么,如何理想地使用 FOUND 并实现乐观并发,同时允许应用程序区分差异?

我猜,当

version
!= 时,人们可以提出一个特殊的例外
in_version.
但是如何呢?

这将使应用程序根据特定的异常类型控制其流程。我不喜欢那样,但是这里可以吗?

解决这个问题没有一个标准吗?我使用 Npgsql 作为数据库接口。

我尝试寻找类似的例子,但没有找到任何适用的。

c# sql .net postgresql concurrency
1个回答
0
投票

您想要返回三种状态之一:

  • 该行不存在
  • 该行存在,但版本已更改
  • 该行可以被删除

我建议你使用整数或枚举来编码这三种状态。

关于功能实现:

DECLARE
   current_version bigint;
   row_id tid;
BEGIN
   -- find and lock the row if it exists
   SELECT version, ctid
   INTO current_version, row_id
   FROM institution
   WHERE id = in_id
   FOR UPDATE;

   IF NOT FOUND THEN
      RETURN 0;
   END IF;

   -- give up if the row was modified
   IF current_version <> in_version THEN
      RETURN 1;
   END IF;

   DELETE FROM institution
   WHERE ctid = row_id;

   RETURN 2;
END;
© www.soinside.com 2019 - 2024. All rights reserved.