SELECT LAST_INSERT_ID() 使用准备好的语句后返回 0

Posted

技术标签:

【中文标题】SELECT LAST_INSERT_ID() 使用准备好的语句后返回 0【英文标题】:SELECT LAST_INSERT_ID() returns 0 after using prepared statement 【发布时间】:2011-02-26 01:49:39 【问题描述】:

我正在使用 mysql 和准备好的语句来插入 BLOB 记录(jpeg 图像)。执行准备好的语句后,我发出一个SELECT LAST_INSERT_ID(),它返回0。

在我的代码中,我在执行命令之后放置了一个断点,在 MySQL 命令(监视器)窗口中,我发出了SELECT LAST_INSERT_ID(),它返回零。

在 MySQL 命令(监视器)窗口中,我发出一条 SQL 语句来选择所有 ID,最后(唯一)插入的 ID 为 1(一)。

我正在使用:

服务器版本:5.1.46-community MySQL 社区服务器 (GPL) Visual Studio 2008,版本 9。 MySQL 连接器 C++ 1.0.5

我的表说明:

mysql> describe picture_image_data;
+---------------+------------------+------+-----+---------+----------------+
| Field         | Type             | Null | Key | Default | Extra          |
+---------------+------------------+------+-----+---------+----------------+
| ID_Image_Data | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| Image_Data    | mediumblob       | YES  |     | NULL    |                |
+---------------+------------------+------+-----+---------+----------------+
2 rows in set (0.19 sec)

使用 MySQL 监视器的结果:

mysql> select ID_Image_Data
    -> from picture_image_data;
+---------------+
| ID_Image_Data |
+---------------+
|             1 |
+---------------+
1 row in set (0.00 sec)

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                0 |
+------------------+
1 row in set (0.00 sec)

准备好的语句:

INSERT INTO Picture_Image_Data
(ID_Image_Data, Image_Data)
VALUES
    (?,
       ?);

以上结果显示 ID_Image_Data 字段为 1,但 LAST_INSERT_ID 为 0。该表是在执行此语句之前创建的,因此这是表中唯一的记录。


编辑:

我将 ID 字段设置为零,将下一个字段设置为 C++ std::istream *。根据MySQL Manual Page for LAST_INSERT_ID()

如果将行的 AUTO_INCREMENT 列设置为非“魔术”值(即,非 NULL 且非 0 的值),LAST_INSERT_ID() 的值不会改变强>)。

LAST_INSERT_ID() 应该返回 1,因为准备好的语句中的 ID 值为 0。


我是否需要为获取 LAST_INSERT_ID 编写准备好的语句?

搜索网络显示使用自定义 MySQL API,但使用 php 和其他 cmets 表示需要另一个连接。

【问题讨论】:

Last_insert_id 是特定于连接的,您在哪里执行准备好的插入? 【参考方案1】:

LAST_INSERT_ID 仅适用于在 auto_increment 字段上创建的自动生成的主键。在您的情况下,您似乎明确提供了 id,因此未设置最后插入 id。

这是明确的:

mysql> insert into test (id, name) VALUES (5, 'test 2');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                0 |
+------------------+
1 row in set (0.00 sec)

这是隐含的:

mysql> insert into test (name) values ('test');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                3 |
+------------------+
1 row in set (0.00 sec)

【讨论】:

我提供的 ID 字段为零。根据手册页,dev.mysql.com/doc/refman/5.0/en/…,如果将行的 AUTO_INCREMENT 列设置为非“魔术”值(即非 NULL 且不是 0)。 所以它应该可以工作。 嗯,你是对的......我刚试过,它在 mysql 控制台中工作。我对 C++ 连接器不是很熟悉...但是由于您可以控制语句,因此只需删除该列的插入即可修复它...【参考方案2】:

看起来问题出在 MySQL C++ 连接器上。

    LAST_INSERT_ID() 返回 0 时 ID 字段为空,显式 插入。 LAST_INSERT_ID() 时返回 0 未指定 ID 字段, 隐式插入。

我尝试从命令行(监视器)插入BLOB(JPEG 图像),它可以工作:

mysql> describe picture_image_data;
+---------------+------------------+------+-----+---------+----------------+
| Field         | Type             | Null | Key | Default | Extra          |
+---------------+------------------+------+-----+---------+----------------+
| ID_Image_Data | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| Image_Data    | mediumblob       | YES  |     | NULL    |                |
+---------------+------------------+------+-----+---------+----------------+
2 rows in set (0.03 sec)
mysql> PREPARE blob_stmt
    ->     FROM 'INSERT INTO picture_image_data (ID_Image_Data, Image_Data) VALUES (?, LOAD_FILE(?))';
Query OK, 0 rows affected (0.02 sec)
Statement prepared

mysql> SET @id = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> SET @c = 'KY_hot_brown_picture.jpg';
Query OK, 0 rows affected (0.00 sec)

mysql> EXECUTE blob_stmt USING @id, @c;
Query OK, 1 row affected (0.15 sec)

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                2 |
+------------------+

1 row in set (0.00 sec)

目前,解决方法是使用 SQL 语句插入带有预准备语句的 BLOB,而不是使用 MySQL C++ 连接器 API。

【讨论】:

【参考方案3】:

您不能指望在 mysql 命令行客户端上发出 SELECT LAST_INSERT_ID() 来为您提供在 C++ 代码中生成的最后插入的值。

LAST_INSERT_ID() 为您提供给定连接上最后一个自动生成的 ID。显然,您的 C++ 程序和 mysql 客户端使用 2 个不同的连接到 mysql 服务器。

(并且 LAST_INSERT_ID() 也应该在 INSERT 之后使用,在 INSERT 和 SELECTLAST_INSERT_ID() 之间不要有其他 SQL 语句)

【讨论】:

在代码中,LAST_INSERT_ID() 的返回值为零。我将更改代码以仅使用 select 语句而不是prepared statement API。 当我使用程序在没有准备好的语句的情况下将记录插入表中时,我可以通过命令行检查LAST_INSERT_ID,结果是正确的。 @Thomas Matthews 你不能相信这种情况。尚不清楚您的问题是在代码中执行此操作,还是您的实际问题是在另一个连接的终端中运行 SELECT LAST_INSERT_ID() - 这无论如何都不应该工作

以上是关于SELECT LAST_INSERT_ID() 使用准备好的语句后返回 0的主要内容,如果未能解决你的问题,请参考以下文章

关于SELECT LAST_INSERT_ID()的使用规则

MySQL LAST_INSERT_ID() 与 INSERT INTO tablea SELECT FROM tableb

select last_insert_id()使用注意事项

SELECT LAST_INSERT_ID() *更新

阿里读写分离数据源SELECT LAST_INSERT_ID()获取不到id

在Spring中用select last_insert_id()时遇到问题