В рамках процесса сохранения в одной из моих моделей генерируется контрольная сумма md5 всей записи и сохраняется вместе с записью.Контрольная сумма md5 содержит сжатое представление всей записи, включая все атрибуты EAV и т. Д. Это делает предотвращение абсолютных дубликатов очень простым и эффективным.
Я не использую уникальный индекс для этой контрольной суммы по определенной причине, я хочувсе это должно быть молчаливым, то есть если пользователь отправляет дубликат, то приложение просто молча игнорирует его и возвращает уже существующую запись.Это обеспечивает обратную совместимость с устаревшими приложениями и API.
Я использую Eloquent от Laravel.Поэтому, как только запись была создана и перед фиксацией приложения делает следующее:
$taxonRecords = TaxonRecord::where('check_sum', $taxonRecord->check_sum)->get();
if ($taxonRecords->count() > 0) {
DB::rollBack();
return $taxonRecords->first();
}
Однако недавно я столкнулся с инцидентом 60 000/1 выстрела (шансы, основанные на количестве записей в то время).Один дубликат попал в базу данных с той же контрольной суммой.Просматривая журналы, я заметил, что время создания было идентичным с точностью до секунды.Дальнейшее изучение журналов Apache показало действительный POST, но POST был продублирован.Я предполагаю, что пользовательский браузер неисправен или что-то в этом роде, но оба сообщения POSTS пришли одновременно, что привело к двум одновременным транзакциям.
Мой вопрос состоит в том, как я могу убедиться, что транзакция и ее значение SELECT
для предыдущей контрольной суммы равно Atomic & Isolated.Исходя из моего прочтения, ответ лежит в https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html и уровнях изоляции.
Если транзакция A и транзакция B поступают на сервер одновременно, то они не должны выполняться рядом, но должны ждатьпервый, чтобы закончить.