我是否需要事务才能在序列中获取正确的最后插入ID?

时间:2018-04-12 00:01:35

标签: php mysql pdo transactions

我有一个名为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吗?

3 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

我认为你应该没事,因为在MySQL中它与连接有关,而且该请求应该使用相同的连接。其他请求可能会在递增表中的最高ID的同时发生,但不应返回这些值。

MySQL docs

中解释得很清楚
  

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

答案 2 :(得分:1)

您可以使用trycatch将其包围,并使用PDO begintransactioncommitrollback功能。可以在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最好应用良好的编码实践,而不是一时兴起,希望最好。 :)