PostgreSQL函数是原子的吗? (ID生成)

时间:2014-09-21 11:07:56

标签: postgresql sequence auto-increment

让'说我在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

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

非常感谢您的帮助。

1 个答案:

答案 0 :(得分:3)

  

假设有两个不同的用户几乎同时运行它。他们可以获得相同的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中运行。