Hibernate сохраняет устаревшие данные с помощью hibernate.jdbc.batch_versioned_data
Среда
Hibernate 4.2
ojdbc6 - Oracle 11.2.0.3.0 JDBC 4.0
Oracle Database 11g
Проблема
Мы следовали многим рекомендациям, чтобы настроить пакетную обработку Hibernate следующим образом:
<property name="hibernate.jdbc.batch_size">100</property>
<property name="hibernate.order_inserts">true</property>
<property name="hibernate.order_updates">true</property>
<property name="hibernate.jdbc.batch_versioned_data">true</property>
Мы проверили наши журналы и увидели, что сгенерированные операторы SQL являются пакетными. Однако, если две транзакции одновременно изменяют одни и те же строки версионных сущностей, Hibernate успешно зафиксирует их обе, что приведет к потере конфликтующих обновлений в транзакции, которая зафиксировала последнюю (бесконфликтные данные сохраняются в обеих транзакциях, поэтому последняя транзакция покидает базу данных в противоречивом состоянии).
Удивительно, но очень мало документации по этому поведению. Официальная документация Hibernate гласит:
hibernate.jdbc.batch_versioned_data
Установите для этого свойства значение true, если ваш драйвер JDBC возвращает правильное количество строк из executeBatch(). Обычно безопасно включить эту опцию. Hibernate будет использовать пакетный DML для автоматически версионных данных. По умолчанию false.
Обычно безопасно? Мы почти отправили это в производство, прежде чем заметили, что вся версия не работает.
Мы погуглили блог, опубликованный пять лет назад, в котором описывается эта странность; по-видимому, Hibernate долгое время ничего не делал по этому поводу.
Есть ли какая-то причина, почему Hibernate ведет себя так? Он получает информацию от драйвера jdbc о том, что количество обновленных строк неизвестно, почему он не выдает исключение для его указания, а создает впечатление, что проверка версии прошла успешно?
1 ответ
Драйвер оракула должен вернуть правильное количество строк. Я буду удивлен, если это не так. Удалось ли вам подтвердить, что результаты, полученные водителем, верны? Вы можете включить протоколирование Hibernate, чтобы проверить это.
Пара вещей для проверки:
Зарегистрируйте фактический SQL, отправляемый в БД, и убедитесь, что столбец версии упоминается в предложении where. Не уверен, что если журналы SQL регистрируются с помощью журналирования Hibernate с пакетной обработкой, вам, возможно, придется прибегнуть к другому способу регистрации SQL-запросов (например, p6spy).
Если во время одновременных обновлений количество строк возвращается правильно, то приложение работает нормально. Подтвердите это, проверив, что значения столбца версии обновлены исправлены.
Обновление Согласно следующей ссылке, эта проблема присутствовала с драйвером Oracle до 11g и исправлена в версии 12c
https://hibernate.atlassian.net/browse/HHH-3360
Для предыдущих версий Oracle есть некоторая дополнительная информация, которая должна быть полезной, т. Е. Предоставляется нестандартное решение.
Дополнительные ресурсы: https://hibernate.atlassian.net/browse/HHH-5070