Что касается проблем с параллелизмом, у вас есть 'простой' способ предотвратить любые проблемы с параллелизмом во втором методе, внутри вашей транзакции выполните выборку в строке статей (теперь For update
неявно) , Любая одновременная вставка в ту же статью не сможет получить такую же блокировку и будет ждать вас.
С новыми уровнями изоляции по умолчанию, даже не используя уровень сериализации в транзакции, вы не увидите одновременной вставки в таблицу голосования до конца транзакции. Таким образом, ваша сумма должна оставаться согласованной или выглядеть как согласованная . Но если при одновременной транзакции вставить голосование по той же статье и зафиксировать перед вами (а эта вторая транзакция не увидит вашу вставку), последняя транзакция, которая будет зафиксирована, перезапишет счетчик, и вы потеряете 1 голос. Так что выполните блокировку строки для статьи, используя select перед (и, конечно, выполняйте свою работу в транзакции). Это легко проверить, открыть 2 интерактивных сеанса на MySQL и начать транзакции с BEGIN.
Если вы используете триггер, вы находитесь в транзакции по умолчанию. Но я думаю, что вам следует также выполнить выборку в таблице статей, чтобы сделать неявную блокировку строки для одновременного запуска триггеров (сложнее проверить).
- Не забудьте удалить триггеры.
- Не забывайте триггеры обновления.
- Если вы не используете триггеры и остаетесь
в коде будьте осторожны каждый
вставить / удалить / обновить запрос при голосовании
следует выполнить блокировку строки на
соответствующая статья, прежде чем в
сделка. Это не очень сложно
забудь одну.
Последнее замечание: совершать более сложные транзакции перед началом использования транзакции:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Таким образом, вам не нужно блокировать строки в статьях, MySQL обнаружит, что происходит потенциальная запись в ту же строку, и заблокирует другие транзакции, пока вы не закончите. Но не используйте то, что вы вычислили из предыдущего запроса . Запрос на обновление будет ожидать снятия блокировки статей, когда блокировка снимается с помощью 1-й транзакции COMMIT
, для подсчета необходимо снова выполнить вычисления SUM
. Таким образом, запрос на обновление должен содержать SUM
или сделать дополнение.
update articles set nb_votes=(SELECT count(*) from vote) where id=2;
И здесь вы увидите, что MySQL умный, обнаруживается тупик, если две транзакции пытаются это сделать, в то время как вставка выполняется одновременно. На уровнях сериализации я не нашел способа получить неправильное значение с помощью:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
insert into vote (...
update articles set nb_votes=(
SELECT count(*) from vote where article_id=xx
) where id=XX;
COMMIT;
Но будьте готовы обработать разрывающую транзакцию, которую вы должны повторить.