如何从 LAST_INSERT_ID(`my_column`+1) 获取表达式的值?

Posted

技术标签:

【中文标题】如何从 LAST_INSERT_ID(`my_column`+1) 获取表达式的值?【英文标题】:How to get the value of expression from LAST_INSERT_ID(`my_column`+1)? 【发布时间】:2020-11-01 03:12:52 【问题描述】:

数据库类型: MariaDB 表引擎: InnoDB

我有一个表,里面有一个值正在递增的列(不是自动的,在这个表中没有插入)

当我在 phpMyAdmin 中运行以下 SQL 查询时,它可以正常工作:

UPDATE `my_table` 
    SET `my_column` = LAST_INSERT_ID(`my_column` + 1) 
WHERE `my_column2` = 'abc'; 
SELECT LAST_INSERT_ID();

当查询发生时,上面返回了my_column 表的最后一个值。此查询直接取自有关锁定的 mysql 文档:https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html(到底部),当您不希望计数器受到其他连接的影响时,这似乎是使用计数器的推荐方式。

我的 PDO:

try 
    $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
    // set the PDO error mode to exception
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            
    $sql = "UPDATE `my_table` 
                SET `my_column` = LAST_INSERT_ID(`my_column` + 1) 
                WHERE `my_column2` = 'abc'; 
            SELECT LAST_INSERT_ID();";

    // Prepare statement
    $stmt = $conn->prepare($sql);

    // execute the query
    $stmt->execute();

    $result = $stmt->fetchColumn(); // causes general error
    $result = $stmt->fetch(PDO::FETCH_ASSOC);// causes general error

    // echo a message to say the UPDATE succeeded
    echo $stmt->rowCount() . " records UPDATED successfully";
        
 catch(PDOException $e)             
    echo $sql . "<br>" . $e->getMessage();        

$conn = null;

确切的错误SQLSTATE[HY000]: General error,如果我删除我尝试获取结果的行,它会更新列,但我仍然没有返回结果......我如何执行更新查询并获得选择像我在 phpMyAdmin 中运行它时那样一次性完成?这一切都需要按照 MySQL 文档的规定一次性完成,因此我不会遇到两个连接可能获得相同计数器的问题。

【问题讨论】:

不要无缘无故地捕获异常。捕获和显示错误消息完全没有意义。 @Dharman 谢谢,但我将如何获得我想要的价值?我还从教程中获取了 PDO 的 sn-p,我以前从未真正使用过 PDO,但我想转向它。为什么我不应该捕获异常,以便以后可以执行诸如创建日志之类的任务,以便以后查看?我刚刚发布了 sn-p 如果真的发生异常我会做更多的工作 供阅读php.net/manual/en/pdo.lastinsertid.php 错误日志记录应该是您应用程序的通用任务。如果你不知道如何实现一个复杂的错误记录器,那就让 PHP 来做吧。 PHP 内置了一个更简单的错误记录器。捕获 PDO 错误以显示错误消息没有任何用处,因为无论如何都会将异常转换为文本消息。 @Dharman 我认为 PDO 可以一次执行多个查询,假设仿真已开启。 【参考方案1】:

无需执行SELECT LAST_INSERT_ID();。 PDO 会自动为您保存该值,您可以将其从 PDO 中取出。

只需这样做:

$conn = new PDO("mysql:host=$servername;dbname=$dbname;charset=utf8mb4", $username, $password, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
        
$sql = "UPDATE `my_table` 
            SET `my_column` = LAST_INSERT_ID(`my_column` + 1) 
            WHERE `my_column2` = 'abc'";

// Prepare statement
$stmt = $conn->prepare($sql);

// execute the query
$stmt->execute();

$newID = $conn->lastInsertId();

lastInsertId() 将为您提供LAST_INSERT_ID() 评估的参数值。

【讨论】:

你能肯定地说这会防止多个连接获得重复的计数器吗?或者 SELECT FOR UPDATE 会是更好的方法吗?您上面的这种方法似乎是 99.9% 的证明,但我不是 DBA @UriahsVictor LAST_INSERT_ID 只会给你当前会话的 ID。这是安全的。您无法从另一个连接中获取 ID。 我还使用-&gt;query() 编写了一个快速测试,因为没有什么真正值得准备的,而且效果很好,非常惊讶!但是学到了一些东西,所以这很好。不确定它是否应该这样做,它并没有多大意义:)

以上是关于如何从 LAST_INSERT_ID(`my_column`+1) 获取表达式的值?的主要内容,如果未能解决你的问题,请参考以下文章

如何选择last_insert_id?

MYSQL LAST_INSERT_ID 未按预期工作。我该如何解决?

是否有等效于 LAST_INSERT_ID 的时间戳?

是否可以从不同的数据库中获取 LAST_INSERT_ID() ?

MySQL 从存储过程中检索 last_insert_id

如何在 WebMatrix 中使用 LAST_INSERT_ID()