Я не уверен, почему вы думаете, что @Transactional
должен заставить ваш OptimisticLockingException
уйти.
Оптимистическая блокировка - это параллельность различных транзакций.
Он работает путем увеличения версии в каждой транзакции, а также проверки обновлений о том, что версия по-прежнему не изменилась с момента загрузки объекта.
При высокой нагрузке это часто не удается для серии событий, подобных этой:
- Транзакция 1 (T1) загружает строку, скажем, с версией 23.
- Транзакция 2 (T2) загружает ту же строку с той же версией 23.
- T1 обновляет счет, увеличивая значение до 24, и фиксирует изменение этого значения видимым для других транзакций.
- T2 также пытается обновить строку, но версия больше не 23, поэтому вы получаете исключение оптимистической блокировки.
- Вам следует перезапустить T2, пока он не сможет фактически обновить базу данных.
Обратите внимание, что ни одна из транзакций не блокирует блокировку строки.
В большинстве случаев это хорошо, поскольку повышает производительность.
Эта выгода исчезнет, если число 4 часто встречается.
Когда вы делаете «сырое ОБНОВЛЕНИЕ», которое, как мне кажется, выглядит примерно так: UPDATE log set counter = counter + 1 WHERE ...
, оптимистическая блокировка не происходит.
Вместо этого вы используете в основном пессимистическую блокировку: вы блокируете строку, которую хотите обновить, когда читаете ее.
Это происходит неявно, так как чтение и запись происходят в одном выражении.
Это означает, что похожий процесс, описанный выше, теперь будет происходить следующим образом:
- Транзакция 1 (T1) обновляет строку, блокирующую ее.
- Транзакция 2 (T2) пытается обновить ту же строку, но блокируется блокировкой и вынуждена ждать.
- T1 фиксирует свою транзакцию, делая изменения видимыми для других транзакций и снимая блокировку.
- T2 теперь может продолжить и обновить строку на основе измененного значения от T1.
Блокировка ограничивает пропускную способность вашего приложения, особенно когда транзакции длинные и если блокируются строки, которые на самом деле не обновляются в конце.
В вашем примере это не так, но в более типичном примере, когда пользователь загружает строку, чтобы посмотреть на нее и, возможно, отредактировать ее, она встречается гораздо чаще.
В вашем случае подход с прямым обновлением кажется более подходящим.
Просто убедитесь, что транзакции максимально короткие.