неправильное поведение mysql_insert_id и last_insert_id - PullRequest
7 голосов
/ 09 декабря 2011

У меня есть эта таблица

 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));

Запустив этот код дважды,на моем компьютере результат 1-й

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

2-й

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

Как видите, оба раза mysql_insert_id () возвращает одно и то же значение "1", для меня это нормально,потому что я хочу знать реальный идентификатор после вставки, но не следующее значение auto_increment.

Но когда я запускал этот код в другой среде дважды: 1-й

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

2-й

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

Как вы можете видеть разницу, результат во второй раз mysql_insert_id () возвращает то же значение, что и last_insert_id ().

Этот результат ужасен, но я не знаю почему.Мои коды нормально работают в обеих средах в течение 3 месяцев, и до сегодняшнего дня этого не было.может кто-нибудь объяснить?Я обновил версию PHP второй среды до 5.3.8 около 30 дней назад, и никаких других изменений.Это ошибка?

обновление

Я переключаюсь на третий сервер 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;

Также отредактируйте мой скрипт

$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 * ​​1044 *

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"
}

Существует ли системная переменная, управляющая этим поведением?Если кто-то знает это было бы приветствовать.Если решения не существует, единственное, что я могу сделать, это принудительно вставить вставку таким образом, чтобы обновить какое-то поле с другим значением ...

1 Ответ

3 голосов
/ 09 декабря 2011

Я думаю, что вы пытаетесь использовать last_insert_id() - это не тот способ, который вам нужен - в этом случае вы ничего не вставляете, поэтому вам также не следует доверять возвращаемому значению. От Документы MySQL :

Если таблица содержит столбец AUTO_INCREMENT и INSERT ... UPDATE вставляет строку, функция LAST_INSERT_ID () возвращает Значение AUTO_INCREMENT. Если оператор обновляет строку вместо, 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;

...