Как PDO узнает последний вставленный идентификатор в MySQL? - PullRequest
14 голосов
/ 24 ноября 2010

РЕДАКТИРОВАТЬ: Этот заголовок вопроса изначально был: Как Doctrine узнал последний вставленный идентификатор в MySQL? и был связан с Doctrine ORM mapper. После некоторого поиска я обнаружил, что этот вопрос не относится к Doctrine , но PDO_MySQL , MySQL C API и, наконец, к клиент-серверному взаимодействию MySQL. Я решил изменить название, поэтому, возможно, кто-то найдет ответ на свой вопрос.

Для тех, кто не использует Доктрину: мне было любопытно, почему ниже:

mysql_query("INSERT INTO category (name) VALUES('cat')");
echo mysql_insert_id();

или аналогичный:

$pdo->exec("INSERT INTO category (name) VALUES('cat')");
echo $pdo->lastInsertId();

приведет только к одной позиции (без отдельной SELECT LAST_INSERT_ID()) в журнале:

1701 Query    INSERT INTO category (name) VALUES ('cat')

Оригинальный вопрос:

У меня есть 2 таблицы:

category(id,name)
product(id, name, categoryId)

Я создал новый объект категории и объект продукта. Я назначил объект категории для объекта продукта. Я не устанавливал идентификаторы:

$product = new Product();
$product->name = 'asdf';

$category = new Category();
$category->name = 'cat';

$product->Category = $category;

После этого я сбросил соединение и проверил логи MySQL:

1684 Query  START TRANSACTION
1684 Query  INSERT INTO category (name) VALUES ('cat')
1684 Query  INSERT INTO product (name, categoryid) VALUES ('asdf', '312')
1684 Query  COMMIT

Как Доктрина узнала, что недавно созданный идентификатор категории - 312? В логах больше ничего нет.

Ответы [ 3 ]

23 голосов
/ 24 ноября 2010

Я провел некоторое исследование и просмотр исходного кода, поэтому мой ответ может быть немного неправильным и не точным.

Прежде всего, это не имеет никакого отношения к Доктрине . Doctrine использует PDO_MYSQL . Но внутренне PDO_MYSQL использует то же самое, что и функция mysql_insert_id - встроенная MySQL C API функция - mysql_insert_id.

Причина отсутствия отдельного SELECT LAST_INSERT_ID() заключается в том, что после выполнения оператора (в моем примере INSERT) сервер отвечает данными и некоторыми другими вещами, включенными в OK Packet ), в том числе insert_id. Поэтому, когда мы запускаем mysql_insert_id(), мы не подключаемся к серверу, чтобы получить insert_id - библиотека mysql не должна этого делать - она ​​уже имеет это значение, сохраненное после последнего выполнения запроса (по крайней мере, я так думаю после анализа файл libmysql.c)

OK Пакет описывается здесь: MySQL Generic Response Packets - OK Packet

1 голос
/ 24 ноября 2010

last_insert_id работает только для AUTO_INCREMENT столбцов. Это не будет работать, если вы вставите значение вручную в столбец AUTO_INCREMENT.

Доктрина будет работать, потому что это все равно, что присвоить ей NULL (хотя вы никогда специально этого не пишете) Это вызывает автоматическое увеличение и предоставляет значение для last_insert_id().

Я включил jpg здесь, чтобы вы могли его увидеть. Надеюсь, это поможет!

enter image description here

1 голос
/ 24 ноября 2010

Возможно, позвонив по номеру http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html

...