我是不是需要事务才能按顺序获得正确的最后插入 ID?

Posted

技术标签:

【中文标题】我是不是需要事务才能按顺序获得正确的最后插入 ID?【英文标题】:Do i need transactions to get the correct last inserted ID in a sequence?我是否需要事务才能按顺序获得正确的最后插入 ID? 【发布时间】:2018-09-21 23:40:48 【问题描述】:

我有一个名为 products 的数据库表,我试图在表中插入产品 A,并在产品 A 插入表后返回产品 A 的 ID。我的 php 代码如下:

    public function save(Product $product) : int
       
        $stmt = $this->conn->prepare(
          "INSERT INTO products VALUES(null, ?, ?, ?, ?)"
        );
        $error = ! $stmt->execute([
          $product->name,
          $product->description,
          $product->picturePath,
          $product->userId,
        ]);
        return $error ? -1 : $this->conn->lastInsertId('products.id');   
         

我正在考虑使用此代码可能遇到的问题,我想到的第一个问题是:如果客户请求将产品 A 插入表中,并且在我获得产品 A 的 ID 之前,另一个请求插入产品B,我会得到产品B的ID吗?是的?如果没有,为什么不呢?

第二个问题是:如果我使用事务插入产品A并检索它的id,那么我会得到产品A的id吗?

【问题讨论】:

【参考方案1】:

您可以用trycatch 包围它,并使用PDO begintransaction、commit 和rollback 函数。例子可以在PHP PDO:lastinsertId详细说明

 try  
        $conn->beginTransaction(); 
        $stmt = conn->prepare(
          "INSERT INTO products VALUES(null, ?, ?, ?, ?)"
        );
        $error = ! $stmt->execute([
          $product->name,
          $product->description,
          $product->picturePath,
          $product->userId,
        ]);
        $id =  $conn->lastInsertId();
        $conn->commit(); 
     catch(PDOExecption $e)  
        $conn->rollback(); 
        print "Error!: " . $e->getMessage() . "</br>"; 
     

IMO 最好采用良好的编码实践,而不是一时兴起并希望获得最好的结果。 :)

【讨论】:

我同意在事务中进行所有数据库操作,它确实有助于确保您的数据库处于干净状态。【参考方案2】:

我认为你应该没问题,因为在 mysql 中它与连接绑定,并且该请求应该使用相同的连接。其他请求可能同时发生,递增表中的最高 ID,但不应返回这些值。

MySQL docs 中解释得很好

对于 LAST_INSERT_ID(),最近生成的 ID 保存在 服务器基于每个连接。它不会被另一个人改变 客户。

【讨论】:

谢谢,php代码和mysql服务器之间的连接是如何工作的对我来说很有趣,我会尝试更多地了解它。【参考方案3】:

lastInsertId() 值是每个连接维护的,因此如果有其他连接将数据插入到同一个表中,您不必担心这些;您的价值将是您连接的价值。

如果您使用成功的事务然后回滚,lastInsertId() 仍将保留其值。回滚不会影响lastInsertId() 的当前值。

【讨论】:

谢谢,您是否也从 mysql 文档中获得了这些信息? 其实我试了一下,发现rollback并没有改变值。 好的。我认为这应该是另一个问题:PDOStatement::execute 文档说,如果发生某些故障,将返回 false,但是在 lastInsertedId 文档中,没有提到任何值,以防互联网连接中断等故障,我想我会使用 try /catch 仅用于处理 lastInsertedId 失败,我不会使用任何事务。

以上是关于我是不是需要事务才能按顺序获得正确的最后插入 ID?的主要内容,如果未能解决你的问题,请参考以下文章

我怎样才能限制到最后的orderByChild?

Magento 在事务中间最后插入 id

使用插入排序算法按字母顺序排序 c#

如何使用 DAO 检测 Yii 中事务中的最后一个插入 ID?

如何从 JayData 事务中获取最后插入 ID?

为啥我需要两个 _getch() 才能获得正确的值? [复制]