Есть приложение C#, есть база данных mysql, используется Dapper. Приложение в несколько потоков добавляет записи в БД таким способом:
id = connection.Query<int>("INSERT INTO messages блаблабла; SELECT LAST_INSERT_ID();", message).FirstOrDefault();
Правильно ли я понимаю, что, учитывая многопоточность, SELECT LAST_INSERT_ID()
в данном контексте вероятно может выдавать неправильные значения? Или же mysql как-то это учитывает?
Как сказано в документации:
When a new AUTO_INCREMENT value has been generated, you can also obtain it by executing a SELECT LAST_INSERT_ID() statement with mysql_query() and retrieving the value from the result set returned by the statement.
When inserting multiple values, the last automatically incremented value is returned.
For LAST_INSERT_ID(), the most recently generated ID is maintained in the server on a per-connection basis. It is not changed by another client. It is not even changed if you update another AUTO_INCREMENT column with a nonmagic value (that is, a value that is not NULL and not 0). Using LAST_INSERT_ID() and AUTO_INCREMENT columns simultaneously from multiple clients is perfectly valid. Each client will receive the last inserted ID for the last statement that client executed.
Таким образом,
Для LAST_INSERT_ID () последний сгенерированный идентификатор сохраняется на сервере для каждого соединения. Это не влияет на других клиентов. [...] Использование столбцов LAST_INSERT_ID () и AUTO_INCREMENT одновременно от нескольких клиентов вполне допустимо. Каждый клиент получит последний вставленный идентификатор для последнего оператора, выполненного клиентом.
Поскольку для MySQL понятия "клиент" и "соединение" эквивалентны в данном контексте, а Ваше приложение "в несколько потоков добавляет записи в БД", то если каждый поток имеет свое собственное соединение с БД - он для MySQL равнозначен отдельному клиенту. И тогда его запросы на LAST_INSERT_ID() никак не влияют на соседние потоки. Если же (прошу пардону, в C# не шарю) эти несколько потоков пользуют одно соединение с базой, как-то по другому решая проблему доступности общего ресурса, то SQL-запрос стоит завернуть в транзакцию, как рекомендует @Андрей NOP:
START TRANSACTION;
INSERT INTO messages блаблабла;
SELECT LAST_INSERT_ID();
COMMIT;
Хотя... Вызов Вашей пары запросов "вставка - чтение" идут в рамках одного обращения к методу connection.Query() и должны отправиться на сервер как один запрос. Соответственно, пока не будет получен на него ответ - общий ресурс "соединение к БД" освободиться не должен бы. И, соответственно, другой поток не получит к нему доступа. Должно бы и так проканать. Но каши маслом не испортишь, лучше все же завернуть в транзакцию. Главное - чтобы при этом у таблицы не был движок MyISAM. :)
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Начал изучать Entity FrameWork подNet MVC, реализую DB First-то бишь есть готовая база Mysql и с помощью EF создаю сущности DBContext и т
Если не вдаваться в подробности, попадаются файлыxlsx которые названы как