Я бы над методом, который запускается в транзакции Repeatable Read просто поставил бы Retryable вот и вся логика повтора. Нужно только правильно указать тип исключения.
Достаточно "хрупкий" код получается, кто то другой залезет и сломает - сделайте лучше на оптимистических блокировках - повторите проигравшую транзакцию ничего страшного
Моё долгосрочное решение - всё-таки будет убрать hibernate, уже столько с ним поел 😁
Это правильно. У хибера много неочевидного и неожиданного поведения. Поэтому, если хочется странного, то лучше без него. Можно использовать JdbcTemplate
Сейчас посмотрел на код hibernate и похоже, что так и должно работать. Там у persistence context просто HashMap, в котором лежат все managed entity. Так что по-простому это не починить. Всем спасибо, ушёл выбирать уже конкретное решение!
дело еще и в том, что когда Вы вызываете метод save() то там под капотом JPA сначала пытается найти эту запись, чтобы понять, что делать INSERT или UPDATE, то есть запросов будет два, а не один.
Вот есть такой вопросик по hibernate + spring-data. Я две одинаковые транзакции в разных потоках и в них делаю findById. Потом делаю тоже самое, но с PESSIMISTIC_WRITE-локом (т.е. select for update). Одна транзакция выигрывает, вторая зависает на локе. Далее в первой транзакции делаю update и commit транзакции. Тут лок отпускается и во второй транзакции получаю объект, но со старым значением (до update), потому что entity уже есть в persistence context. Делаю update и теряю предыдущий update.
Это ожидаемое поведение? Можно ли как-то настроить hibernate, чтобы второй select for update обновлял мою entity?
Не ожидаемое. Должно во втором потоке обновлённое быть
дело еще и в том, что когда Вы вызываете метод save() то там под капотом JPA сначала пытается найти эту запись, чтобы понять, что делать INSERT или UPDATE, то есть запросов будет два, а не один.
Правильно, не шарятся. Но это воспроизводится как раз только для второго селекта внутри сессии. Первый у меня без for update, и если его выключить, то проблема пропадёт. Кеш выключен, это точно