Это два комментария, которые вставляются с одинаковым content_id. Простая вставка комментария снимает блокировку SHARE в строке содержимого, чтобы остановить другую транзакцию, удаляя эту строку, пока первая транзакция не будет завершена.
Однако затем триггер продолжает обновлять блокировку до ИСКЛЮЧИТЕЛЬНОЙ, и это может быть заблокировано одновременной транзакцией, выполняющей тот же процесс. Рассмотрим следующую последовательность событий:
Txn 2754 Txn 2053
Insert Comment
Insert Comment
Lock Content#935967 SHARE
(performed by fkey)
Lock Content#935967 SHARE
(performed by fkey)
Trigger
Lock Content#935967 EXCLUSIVE
(blocks on 2053's share lock)
Trigger
Lock Content#935967 EXCLUSIVE
(blocks on 2754's share lock)
Так что тупик.
Одно из решений заключается в том, чтобы немедленно установить эксклюзивную блокировку строки содержимого до вставки комментария. т.е.
SELECT 1 FROM content WHERE content.id = 935967 FOR UPDATE
INSERT INTO comment(.....)
Другое решение состоит в том, чтобы просто полностью избежать этой схемы «кэшированных подсчетов», кроме случаев, когда вы можете доказать, что это необходимо для производительности. Если это так, подумайте о том, чтобы сохранить кэшированный счет где-то, кроме таблицы содержимого, например выделенный стол для прилавка. Это также сократит трафик обновлений к таблице контента при каждом добавлении комментария. Или, может быть, просто повторно выберите количество и используйте memcached в приложении. Нельзя обойти стороной тот факт, что где бы вы ни хранили этот кэшированный счетчик, он будет задыхаться, его нужно безопасно обновлять.