【问题标题】:Can $pdo->lastInsertId($seqname) be trusted?$pdo->lastInsertId($seqname) 可以信任吗?
【发布时间】:2013-08-09 14:37:48
【问题描述】:

在使用 PostgreSQL 时,我不得不将序列的名称传递给 lastInsertId()。这让我认为查询没有从数据库返回 id,而是 lastInsertId($seqname) 正在执行一个额外的查询,可能容易出现竞争条件(如果同时插入另一行,我会得到错误的结果)。

阅读文档时,我发现了这条评论,它表达了同样的想法:http://www.php.net/manual/en/pdo.lastinsertid.php#83440。它已经 5 年了,我找不到任何更新的东西。

你怎么看?

【问题讨论】:

    标签: php postgresql pdo


    【解决方案1】:

    为了使这个可靠,您必须:

    • 一次只插入一条记录;
    • 指定序列名称;和
    • 通过使用会话级连接池或使用事务级池并在同一事务中同时执行插入和lastInsertId,对同一会话执行后续查询。

    如果 PDO 使用 INSERT ... RETURNING 并从结果集中获取插入的 ID,那会好很多 。这样你就会得到一个理智的价值:

    INSERT INTO mytable(col1,col2)
    VALUES (1,'a'),  (2,'b'),  (3,'c')
    RETURNING id;
    

    使用lastInsertId,您将仅获得插入的最后一行的 ID - 而您不能假设前面的行具有连续的 ID。如果lastInsertId42,则保证前面的行是4140,因为可能存在同时声明ID 的插入。

    所以“是lastInsertId 安全”的答案是......有点。如果在正确使用currval 所需的约束范围内使用它是安全的,但它远非理想。我个人会避免使用INSERT ... RETURNING

    【讨论】:

    • 哇,这就是答案!所以我的问题是在使用事务级池时,我必须小心。我不能真正使用没有 $seqname 的 lastInsertId() ,不知道为什么,所以我不会为此而堕落。谢谢!
    • 我考虑过使用returning,但是插入语法很烦人,因为我必须逐字段指定。我现在会坚持使用 lastInsertId。
    【解决方案2】:

    我敢打赌它使用SELECT currval('seq_name'),它返回每个连接最后生成的。所以它可以被信任。

    【讨论】:

    • “每个连接”。如果我使用游泳池怎么办? (pgbouncer)
    • 你从池中得到一个连接,并且只使用那个连接。
    【解决方案3】:

    序列的唯一目的是保持一致性。

    否则它们将毫无用处。

    【讨论】:

    • 我可以看到它们在插入时如何保持一致性,但尚不清楚这是否适用于其他任何事情(比如在我的应用程序中找出插入的内容,而不是在数据库中)。你确定这会正常工作吗?即使我使用的是游泳池? (pgbouncer)
    • 再说一遍:如果它不工作,它就根本不存在。请不要把自己当成唯一了解问题的人。有 1000 多个开发人员正在使用此功能。
    • 再次:您知道它有效吗,或者您只是使用“您的常识”并假设一切正常,因为很多人都在使用它?
    猜你喜欢
    • 2013-10-18
    • 1970-01-01
    • 2011-08-21
    • 2020-01-01
    • 1970-01-01
    • 2016-10-24
    • 2011-02-10
    • 2010-09-22
    • 2012-06-07
    相关资源
    最近更新 更多