Альтернатива PDO::lastInsertId/mysql_insert_id

Я всегда слышу, что использование «lastInsertId» (или mysql_insert_id(), если вы не используете PDO) — это зло. В случае триггеров это очевидно, потому что он может вернуть что-то, что совершенно не является последним идентификатором, созданным вашим INSERT.

$DB->exec("INSERT INTO example (column1) VALUES ('test')");
// Usually returns your newly created ID.
// However when a TRIGGER inserts into another table with auto-increment:
// -> Returns newly created ID of trigger's INSERT
$id = $DB->lastInsertId();

Какая альтернатива?


person BlaM    schedule 14.11.2008    source источник


Ответы (6)


Если вы пойдете по пути ADOdb (http://adodb.sourceforge.net/), то вы можете создайте идентификатор вставки перед началом и явно укажите идентификатор при вставке. Это может быть реализовано переносимо (ADOdb поддерживает массу различных баз данных...) и гарантирует, что вы используете правильный идентификатор вставки.

Тип данных PostgreSQL SERIAL аналогичен, за исключением того, что он предназначен для каждой таблицы/последовательности, вы указываете таблицу/последовательность, для которой хотите получить последний идентификатор вставки, когда запрашиваете его.

person Keith Palmer Jr.    schedule 14.11.2008
comment
Выглядит довольно интересно. Какое влияние эта техника оказывает на производительность? - person BlaM; 14.11.2008
comment
Да, но что делать, если вы застряли с PDO? - person Elijah; 24.02.2010
comment
Вы можете написать свой собственный код, чтобы делать то же самое, что делает ADOdb, за исключением использования PDO. По сути, вы получаете отдельную таблицу для хранения последовательности, которую вы ЗАПИСЫВАЕТЕ LOCK перед увеличением значения последовательности при получении нового идентификатора. - person Keith Palmer Jr.; 25.02.2010
comment
Это не должно сильно влиять на производительность, это всего лишь очень простая таблица, которая блокируется, извлекает одну запись, увеличивается, разблокируется. Я не заметил никакой разницы в производительности ни в одном приложении, с которым я его использовал. Помните: сначала наладьте работу, а потом настройте производительность. - person Keith Palmer Jr.; 25.02.2010

ИМХО, это считается «злом» только потому, что оно вряд ли есть в какой-либо другой базе данных SQL (если таковая имеется).

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

person Alnitak    schedule 14.11.2008
comment
По крайней мере, MSSQL имеет ту же функцию. На моей старой работе использование идентификатора вставки вызывало большие головные боли, когда кто-то добавлял в таблицу триггер, который ломал весь сайт - без очевидной причины для тех, кто не знал об этом триггере... - person BlaM; 14.11.2008

Одной из альтернатив является использование вместо этого последовательностей, поэтому вы сами генерируете идентификатор перед вставкой.

К сожалению, они не поддерживаются в MySQL, но такие библиотеки, как Adodb, могут эмулировать их, используя другую таблицу. Однако я думаю, что сама эмуляция будет использовать lastInsertId() или эквивалентную... но, по крайней мере, у вас меньше шансов иметь триггер в таблице, которая используется исключительно для последовательности

person Tom Haigh    schedule 14.11.2008

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

person markus    schedule 14.11.2008
comment
Очевидно, это также работает, но ИМХО блокировка еще более опасна в высокопроизводительных веб-приложениях... - person BlaM; 14.11.2008

Это несложно и неэффективно, но если вставленные вами данные содержат уникальные поля, то SELECT, очевидно, может дать то, что вам нужно.

Например:

INSERT INTO example (column1) VALUES ('test');
SELECT id FROM example WHERE column1 = 'test';
person Peter Howe    schedule 14.11.2008
comment
Очевидно ;) - Но также очевидно довольно уродливо ;) - person BlaM; 14.11.2008

Вы можете попробовать это:

$sql = "SELECT id FROM files ORDER BY id DESC LIMIT 1";
$PS = $DB -> prepare($sql);
$PS -> execute();
$result = $PS -> fetch();
person mikeyD    schedule 17.07.2012
comment
Это не альтернатива в средах с интенсивным движением. Вы будете постоянно получать неправильные идентификаторы. - person BlaM; 02.08.2012