mysql_insert_id和last_insert_id错误的行为

Mat*_*t.Z 7 php mysql mysql-insert-id last-insert-id

我有这张桌子

 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  ;
Run Code Online (Sandbox Code Playgroud)

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));
Run Code Online (Sandbox Code Playgroud)

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

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "1"
}
Run Code Online (Sandbox Code Playgroud)

第2

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "2"
}
Run Code Online (Sandbox Code Playgroud)

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

但是,当我在另一个环境中运行此代码两次时:第1次

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "1"
}
Run Code Online (Sandbox Code Playgroud)

第2

int(2)
array(1) {
  ["last_insert_id()"]=>
  string(1) "2"
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的那样,第二次的结果mysql_insert_id()返回与last_insert_id()相同的值.

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

更新

我切换到第三个mysql服务器(5.1.38-log),第二个插入返回int(0)数组(1){["last_insert_id()"] => string(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;
Run Code Online (Sandbox Code Playgroud)

还要编辑我的脚本

$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));
Run Code Online (Sandbox Code Playgroud)

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

5.0.24a社区-NT

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "2"
}
Run Code Online (Sandbox Code Playgroud)

5.0.51a日志

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "2"
}
Run Code Online (Sandbox Code Playgroud)

5.1.38日志

int(1)
array(1) {
  ["last_insert_id()"]=>
  string(1) "0"
}
Run Code Online (Sandbox Code Playgroud)

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

Aur*_*mas 3

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

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

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

但是,您可以使用 LAST_INSERT_ID(expr) 来解决此问题。假设 id 是 AUTO_INCREMENT 列。要使 LAST_INSERT_ID() 对更新有意义,请按如下方式插入行:

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