У меня такой же вопрос, как описано here, а также я думаю, что ответ https://stackoverflow.com/a/22343265/297487 - хорошее решение, но у меня есть еще один вопрос об этом ответе.Является ли этот MySQL триггером потокобезопасным?
Является ли следующий триггер (скопированный из ответа) потокобезопасным? Я имею в виду, если две параллельные записи, вставленные в таблицу, столбец «приоритет» (как описано в вопросе) имеет постоянное значение (то же значение, что и id)?
delimiter //
drop trigger if exists bi_table_name //
create trigger bi_table_name before insert on table_name
for each row begin
set @auto_id := (SELECT AUTO_INCREMENT
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME='table_name'
AND TABLE_SCHEMA=DATABASE());
set new.priority= @auto_id;
end;
//
delimiter ;
Как мы интерпретируем предложение «для каждой строки»? Предположим, что MySQL хочет вставить две параллельные строки. Как работает этот триггер?
Одно из объяснений заключается в следующем:
MySQL блокирует таблицу и перед вставкой одной из строк (одна из параллельной записи) начинается триггер MySQL и получает текущее значение AUTO_INCREMENT, и устанавливает его в столбец «приоритет», а затем вставляет запись. После этого MySQL начинает вставлять другую запись, и тогда такая же ситуация применима к новой записи.
Другая интерпретация может быть следующим:
Когда две параллельные записи вставляются в MySQL, MySQL блокирует таблицу, а затем перед вставкой два одновременных записи триггер запускается и «для каждой строки» пункт итерация между двумя записи и установите значение столбца «приоритет» на одно и то же значение, а затем вставьте две параллельные записи в базу данных. В этой ситуации триггер работает не так, как ожидалось.
Какая из приведенных выше интерпретаций верна?
Обновление:
У меня есть следующие таблицы:
CREATE TABLE `t_file` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_persian_ci NOT NULL,
`p_name` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `p_name_2` (`p_name`)
) ENGINE=InnoDB AUTO_INCREMENT=206284 DEFAULT CHARSET=utf8 COLLATE=utf8_persian_ci;
Я хочу, чтобы вставить значение p_name
так же, как id
, когда строка вставлена.
The trigger
, который устанавливает значение p_name
выглядит следующим образом (копируется из вашего кода)
delimiter $$
drop trigger if exists file_p_name $$
create trigger file_p_name before insert on t_file
for each row begin
set @id := (SELECT AUTO_INCREMENT
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME='t_file'
AND TABLE_SCHEMA=DATABASE());
set new.p_name= @id;
end;
$$
delimiter ;
В нашем приложении, я окружать код, который вставляет в t_file
таблицу с try catch
, почти всегда все в порядке, но иногда (в параллельной вставки в t_file
таблицу), я вижу следующее исключение в журнале нашего приложения:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry \'387456\' for key \'p_name_2\''
кажется trigger
работает не так, как ожидалось, или, может быть, я ошибаюсь !!!
кажется ваш ОК, но я загрузил этот код в системе с одной и той же ситуацией, которая имеет много одновременного users.I проинформирует вы о результатах. – Khosro
Я пытаюсь проверить выше триггер в параллельной системе, я создал уникальное ограничение для столбца «приоритет». После трех дней я видел некоторые исключения, указывающие на то, что дублирование столбца «приоритет» в указанной таблице. Так что это кажется выше триггера не является потокобезопасным и имеет некоторые проблемы в параллельной системе. – Khosro
Очень плохо, что MySQL не «после триггера» для обновления строки после ее вставки. – Khosro