mysql_insert_id 和 last_insert_id 错误行为

发布于 2024-12-20 09:02:32 字数 2745 浏览 5 评论 0原文

我有这个表

 CREATE TABLE IF NOT EXISTS `t5` (
  `id` int(11) NOT NULL auto_increment,
  `a` int(11) NOT NULL,
  `b` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `a` (`a`,`b`)
 ) ENGINE=InnoDB DEFAULT CHARSET=latin1  ;

a_b 是一个唯一的键。

我有这样的 php 代码

 $db = DBFactory::getInstance();
 $db->selectDB('test');
 $db->query("insert into t5 (a, b) values(1, 1) on duplicate key update a=1, b=1");
 var_dump(mysql_insert_id());

 $cur = $db->query("select last_insert_id()");
 var_dump(mysql_fetch_assoc($cur));

通过在我的电脑上运行此代码两次,结果是 1st

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "1"
}

2nd

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "2"
}

你可以看到,两次 mysql_insert_id() 返回相同的值“1”,这对我来说很好,因为我想知道插入后的真实 id,而不是下一个 auto_increment 值。

但是当我在另一个环境上运行这段代码两次时: 1st

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "1"
}

2nd

int(2)
array(1) {
  ["last_insert_id()"]=>
  string(1) "2"
}

正如你所看到的差异,第二次的结果 mysql_insert_id() 返回与last_insert_id() 相同的值。

这个结果很可怕,但我不知道为什么。我的代码在这两个环境上运行良好大约 3 个月,直到今天才发生这种情况。有人可以解释一下吗?我确实在大约30天前将第二个环境的PHP版本升级到了5.3.8,没有其他变化。这是一个错误吗?

更新

我切换到第三个mysql服务器(5.1.38-log),第二次插入返回 整数(0) 数组(1){ [“last_insert_id()”] => 字符串(1)“0” 所以

我意识到问题可能与 mysql 版本有关。

最后,我将表定义更改为这个

DROP TABLE IF EXISTS `t5`;
CREATE TABLE IF NOT EXISTS `t5` (
  `id` int(11) NOT NULL auto_increment,
  `a` int(11) NOT NULL,
  `b` int(11) NOT NULL,
  `t` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `a` (`a`,`b`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

还编辑我的脚本

$db = DBFactory::getInstance();
$db->selectDB('test');
$db->query("insert into t5 (a, b, t) values(1, 1, ".time().") on duplicate key update a=1, b=1, t=".time());
//$db->query("insert ignore into t5 (a, b) values(1, 1)");
var_dump(mysql_insert_id());

$cur = $db->query("select last_insert_id()");
var_dump(mysql_fetch_assoc($cur));

不同的mysql服务器返回相同的mysql_insert_id但不同的last_insert_id()

5.0.24a-community-nt

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "2"
}

5.0.51a-log

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "2"
}

5.1.38-log

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "0"
}

是否有任何系统变量控制此行为?如果有人知道那就太好了。如果没有解决方案,我唯一能做的就是像这样强制插入以更新具有不同值的某些字段......

I have this table

 CREATE TABLE IF NOT EXISTS `t5` (
  `id` int(11) NOT NULL auto_increment,
  `a` int(11) NOT NULL,
  `b` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `a` (`a`,`b`)
 ) ENGINE=InnoDB DEFAULT CHARSET=latin1  ;

a_b is a unique key.

And I have php code like this

 $db = DBFactory::getInstance();
 $db->selectDB('test');
 $db->query("insert into t5 (a, b) values(1, 1) on duplicate key update a=1, b=1");
 var_dump(mysql_insert_id());

 $cur = $db->query("select last_insert_id()");
 var_dump(mysql_fetch_assoc($cur));

By running this code twice, on my pc the result is
1st

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "1"
}

2nd

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "2"
}

You can see, both times the mysql_insert_id() return the same value "1", this is fine to me, because I want to know the real id after the insertion , but not the next auto_increment value.

But when I ran this code on another environment twice:
1st

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "1"
}

2nd

int(2)
array(1) {
  ["last_insert_id()"]=>
  string(1) "2"
}

As you can see the difference, the second time's result mysql_insert_id() return the same value as last_insert_id().

This result is horrible, but I don't know why. My codes run fine on both environment for about 3 months, and this never happened until today. can someone explain ? I did upgrade the second environment's PHP version to 5.3.8 about 30 days ago, and no other changes. Is this a bug?

update

I switch to the third mysql server(5.1.38-log), the second insert return
int(0)
array(1) {
["last_insert_id()"]=>
string(1) "0"
}

So I realized that the problem maybe is about mysql version.

At last, I changed table define to this one

DROP TABLE IF EXISTS `t5`;
CREATE TABLE IF NOT EXISTS `t5` (
  `id` int(11) NOT NULL auto_increment,
  `a` int(11) NOT NULL,
  `b` int(11) NOT NULL,
  `t` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `a` (`a`,`b`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Also edit my script

$db = DBFactory::getInstance();
$db->selectDB('test');
$db->query("insert into t5 (a, b, t) values(1, 1, ".time().") on duplicate key update a=1, b=1, t=".time());
//$db->query("insert ignore into t5 (a, b) values(1, 1)");
var_dump(mysql_insert_id());

$cur = $db->query("select last_insert_id()");
var_dump(mysql_fetch_assoc($cur));

Different mysql server return the same mysql_insert_id but different last_insert_id()

5.0.24a-community-nt

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "2"
}

5.0.51a-log

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "2"
}

5.1.38-log

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "0"
}

Is there any system variable control this behavior? If someone know that would be greetful. If there is no solution, the only thing I can do is to force insertion like this to update some field with different value...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

赠意 2024-12-27 09:02:32

我认为你试图使用 last_insert_id() 的方式并不意味着 - 在这种情况下你没有插入任何东西,所以你也不应该相信返回值。来自 MySQL 文档

如果表包含 AUTO_INCRMENT 列和 INSERT ... UPDATE
插入一行,LAST_INSERT_ID()函数返回
自动递增值。如果该语句改为更新一行,
LAST_INSERT_ID() 没有意义。

但是,似乎有一个解决方法(同一文档) - 手动设置last_insert_id:

但是,您可以使用 LAST_INSERT_ID(expr) 解决此问题。
假设 id 是 AUTO_INCREMENT 列。制作 LAST_INSERT_ID()
对于更新有意义,插入行如下:

INSERT INTO 表 (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE
id=LAST_INSERT_ID(id), c=3;

I think you are trying to use last_insert_id() is way that is not meant to be - in these case you are not inserting anything, so you should not trust the return value, either. From MySQL docs:

If a table contains an AUTO_INCREMENT column and INSERT ... UPDATE
inserts a row, the LAST_INSERT_ID() function returns the
AUTO_INCREMENT value. If the statement updates a row instead,
LAST_INSERT_ID() is not meaningful.

However, it appears that there is a workaround for that (same doc) - manually setting last_insert_id:

However, you can work around this by using LAST_INSERT_ID(expr).
Suppose that id is the AUTO_INCREMENT column. To make LAST_INSERT_ID()
meaningful for updates, insert rows as follows:

INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE
id=LAST_INSERT_ID(id), c=3;

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文