【问题标题】:Are PostgreSQL functions atomic? (ID generation)PostgreSQL 函数是原子的吗? (身份证生成)
【发布时间】:2014-11-15 12:03:23
【问题描述】:

假设我在 PostgreSQL 中有以下存储过程。 (请注意,这不是真正的代码。我知道这可以通过另一种更好的方式完成,这只是说明我的问题的一个例子)

CREATE FUNCTION testFunction( ) RETURNS integer AS $$
DECLARE iNewID integer;
BEGIN
  SELECT CurrentID INTO iNewID FROM TestTable; // statement 1

  iNewID := iNewID + 1;

  UPDATE TestTable SET CurrentID=iNewID;  // statement 2

  RETURN iNewID;
END; $$
LANGUAGE PLPGSQL;

假设两个不同的用户几乎同时运行它。他们可以返回相同的ID吗?

我将尝试用其他方式解释。在代码中,我注释了两个语句。如果两个用户同时运行它。该语句的调用顺序是什么。我能确定会是这样吗:

  • 用户 A 声明 1
  • 用户 A 声明 2
  • 用户 B 声明 1
  • 用户 B 声明 2

或者可能是这样(导致相同的ID):

  • 用户 A 声明 1
  • 用户 B 声明 1
  • 用户 A 声明 2
  • 用户 B 声明 2

我希望你能理解我的问题。我真的试图在网上搜索这个问题的答案,但没有运气。这可能是因为我没有任何名字?这叫什么?

非常感谢您的帮助。

【问题讨论】:

    标签: postgresql sequence auto-increment


    【解决方案1】:

    假设两个不同的用户几乎同时运行它。他们可以返回相同的ID吗?

    是的,当然。就像您在事务之外将其作为两个单独的语句运行,在您的应用程序中进行添加一样。

    I wrote about this recently.

    使用SEQUENCE 来确保唯一的 ID。 SERIAL 伪类型使这更容易。请注意,不能保证 ID 是无间隙的;具有以下 ID 是正常的:1、3、4、5、6、9、10、11、14,.. 如果事务回滚,则服务器重新启动等。

    如果这对你来说是个问题,你会想要这样做:

    SELECT CurrentID INTO iNewID FROM TestTable FOR UPDATE;
    ... blah blah ...
    

    ... 这将锁定该行,以便其他事务在当前事务提交或回滚之前无法更新它。这实际上可以使用 PostgreSQL 特定的功能简化为:

      UPDATE TestTable
      SET CurrentID = iNewID
      RETURNING CurrentID;
    

    然后您可以将其包装在 SQL 函数中或使用 RETURN QUERY 在 PL/PgSQL 中运行。

    【讨论】:

    • 非常感谢您的回答和精彩文章的链接!...我只是使用 ID 示例来说明我的问题。这不是我在实际工作中尝试做的事情。对于我的实际工作,不可能编辑 SQL 或使用“FOR UPDATE”。也许我必须研究您文章中提到的 SERIALIZABLE 事务。但我不喜欢的是第二次会议被中止。存储过程不可能以与单个语句相同的方式工作吗?那么,如果两个会话同时启动,其中一个会等待另一个完成然后运行?
    猜你喜欢
    • 1970-01-01
    • 2019-02-23
    • 1970-01-01
    • 1970-01-01
    • 2017-10-11
    • 2021-07-21
    • 1970-01-01
    • 2013-08-01
    • 1970-01-01
    相关资源
    最近更新 更多