Я использую Hibernate StatelessSession для вставки и обновления строк навалом. Не уверен, что jdbc.batch
_size связан с вопросом, но в любом случае в моем приложении я вообще не настраиваю параметр hibernate.jdbc.batch_size
.
Я поставлю на сеанс объект соединения, который уже привязан к потоку к существующей транзакции (управляется Spring). Это делается с помощью Spring DataSourceUtils
. По этой причине я не закрываю сессию без сохранения состояния, когда я закончил обработку данных, потому что мне все еще нужно открыть соединение для нескольких других вещей, пока транзакция не будет завершена.
В основном, что-то вроде этого:
statelessSession = sessionFactory.openStatelessSession(DataSourceUtils.getConnection(...));
// repeat many times
try {
statelessSession.insert(entity);
}
catch (ConstraintViolationException e) {
statelessSession.update(entity);
}
// some more actions
// close transaction
В SQL Server все работает так, как ожидалось. Каждый вызов session.insert(...)
запускает SQL и, возможно, сбой по уникальному ограничению, если я пытаюсь вставить существующую строку. Когда я в конечном итоге совершаю транзакцию, все работает так, как я ожидаю.
Однако в Oracle ничего не происходит. Журналы Hibernate печатают SQL, но он просто не запускается. Кроме того, вставки не сбой, когда они должны.
После отладки кода Hibernate я узнал, что он связан с поведением JDBC. Я решил явно очистить statelessSession
с помощью managedFlush()
. Даже тогда я узнал, что я должен очистить его после каждой команды, иначе он не будет демонстрировать неудачное поведение, которое я хочу.
statelessSession = sessionFactory.openStatelessSession(DataSourceUtils.getConnection(...));
// repeat many times
try {
statelessSession.insert(entity);
((Context) session).managedFlush()
}
catch (ConstraintViolationException e) {
statelessSession.update(entity);
((Context) session).managedFlush()
}
// some more actions not related to statelessSession
// close transaction
Хотя это работает, когда я профилировал свой код, я обнаружил, что теперь он работает медленнее. Даже на SQL Server, где, по-видимому, метод managedFlush()
не имеет ничего общего.
Любая идея, что происходит? Есть ли скрытая конфигурация, которую я могу настроить для достижения желаемого поведения - что-то вроде "авто-флеш" (но без автоматической фиксации, конечно)?
Во-первых, вы должны закрыть сеанс, как только получите исключение, потому что контекст сохранения может остаться в несогласованном состоянии.
Поэтому вы не должны обновлять ни одно исключение.
Цитирование сессии JavaDoc:
Если сеанс вызывает исключение, транзакция должна быть отброшена и сеанс отброшен. Внутреннее состояние сеанса может не соответствовать базе данных после возникновения исключения.
В вашем примере вы можете просто вызвать merge, потому что он работает как в sert/updates:
statelessSession.merge(entity);
Поскольку вы используете MS SQL, вы можете использовать генератор IDENTITY, который отключает доработку JDBC. Последние версии MS SQL добавили поддержку Seqeuneces, которые более дружелюбны с пакетной загрузкой в любом случае.
Вам необходимо включить поддержку пакетной поддержки Hibernate, например:
hibernate.jdbc.batch_size=30
Если вы не устанавливаете это свойство, значение по умолчанию равно 0, поэтому нет пакетной загрузки JDBC по умолчанию.
Почему работает на SQL Server:
SQL-сервер поддерживает READ UNCOMMITTED уровень изоляции. Это означает, что другая транзакция может видеть незафиксированные изменения в таблице.
Почему бы не работать с Oracle:
Oracle не поддерживает READ UNCOMMITTED, он имеет только READ COMMITTED и SERIALIZABLE. Таким образом, другая транзакция из "Oracle SQL Developer" или "Жаба" не может видеть все еще незафиксированные изменения транзакции в вашем приложении.
Давайте скажем "hibernate.jdbc.batch_size = 20", и вы хотите сделать 100 вставок. Ваше приложение отправит вставки как 5 партий, каждая из которых содержит 20 вставок. Другая транзакция "READ UNCOMMITTED" будет видеть каждую отдельную партию. Операция "READ COMMITTED" ничего не увидит, пока ваше приложение не совершит транзакцию, которая создает вставки.