В Быть в спящем режиме ссылке это несколько раз указывается это
Все исключения, выданные, в спящем режиме, являются фатальными. Это означает, что необходимо откатывать транзакцию базы данных и закрыть ток
Session
. Нельзя продолжить работать с aSession
это выдало исключение.
Одно из наших приложений прежней версии использует единственную сессию для обновления/вставления многих записей из файлов в Таблицу базы данных. Каждая запись обновляет/вставляет, сделан в отдельной транзакции, которая затем фиксируется (или откатывается в случае, если ошибка произошла). Затем для следующей записи новая транзакция открыта и так далее. Но та же сессия используется в течение целого процесса, даже если a HibernateException
был пойман посреди обработки. Мы используем Oracle 9i btw с, в спящем режиме 3.24.sp1 на JBoss 4.2.
Читая вышеупомянутое в книге, я понял, что этот дизайн может перестать работать. Таким образом, я осуществил рефакторинг приложение для использования отдельной сессии для каждого рекордного обновления. В модульном тесте с ложной фабрикой сессии я могу проверить, что это теперь запрашивает новую сессию на каждое рекордное обновление.Пока все хорошо.
Однако мы не нашли способа воспроизвести отказ сессии при тестировании целого приложения (это будет стресс-тестом btw, или...?). Мы думали о закрытии слушателя DB, но мы поняли, что приложение сохраняет набор соединений открытым для DB, и слушатель не влиял бы на те соединения. (Это - веб-приложение, активированное один раз в ночь планировщиком, но это может также быть активировано через браузер.) Затем мы пытались уничтожить некоторые из тех соединений в DB, в то время как приложение обрабатывало обновления - это привело к некоторым неудавшимся обновлениям, но затем приложение счастливо продолжало обновлять остальную часть записей. По-видимому, Будьте в спящем режиме, достаточно умно для повторного открытия поврежденных соединений под капотом, не повреждая целую сессию.
Таким образом, это не могло бы быть критической проблемой, в конце концов, поскольку наше приложение, кажется, достаточно устойчиво даже в его исходной форме. Однако проблема продолжает прослушивать меня. Я хотел бы знать:
HibernateException
был брошен (Обновление: и каковы признаки)?При каких обстоятельствах сеанс Hibernate действительно становится непригодным для использования после создания исключения HibernateException?
Интересный вопрос. Я почти уверен, что видел случаи, когда сеанс все еще «работал» после такого исключения. Проблема может в том, что это не гарантируется. Мне нужно еще немного покопаться.
Обновление: Цитата это сообщение от разработчика Hibernate на форумах Hibernate:
Сеанс гибернации следует отбрасывать при возникновении любого исключения. Его можно оставить в несогласованном состоянии относительно базы данных. Это не относится к сеансу только для чтения, поскольку он не использует кэширование на уровне сеанса. В качестве альтернативы вы можете очистить кеш уровня сеанса при возникновении исключения (но мне лично не нравится этот подход, поскольку это не чистое решение и может привести к будущим проблемам и проблемам).
Таким образом, проблема не в том, является ли сеанс
«технически пригодным» или нет, проблема в том, что он может вести себя не так, как ожидалось. И вы явно этого не хотите.
Как воспроизвести это в тесте?
Вы можете намеренно нарушить условие, вызывающее создание подкласса, например, нарушив ограничение целостности, чтобы получить ConstraintViolationException
. Как насчет чего-то вроде этого:
Session session = HibernateUtil.getCurrentSession();
try {
session.beginTransaction();
// execute some code that violates a unique constraint
...
session.getTransaction().commit();
} catch (HibernateException e) {
session.getTransaction().rollback();
}
// keep using the session
try {
session.beginTransaction();
...
session.getTransaction().commit();
} catch (HibernateException e) {
session.getTransaction().rollback();
}
// do we reach this point?
Но я не уверен, что это что-то докажет. Я имею в виду, что если сессия все еще работает, мы можем сделать вывод только для этого конкретного случая.
Обновление: Забудьте мое предложение, оно ничего не докажет. И на самом деле, я думаю, что было бы чрезвычайно сложно (технически и функционально) доказать, что все работает должным образом (и это все еще может быть «случайностью») после HibernateException
.
Итак, вместо того, чтобы что-то доказывать, я полагаю, что правильнее всего следовать рекомендации (или предлагаемой альтернативе, но я бы просто запросил новую сессию
и закрыть
его для каждой транзакции, независимо от того, возникло ли исключение).
Какой термин подходит для такого теста?
Интеграционный тест? Тест на устойчивость?
Создайте подкласс сеанса для тестирования. Реализуйте его, чтобы генерировать исключение в каком-то конкретном сценарии. Используйте тестовую конфигурацию гибернации, которая настраивает спящий режим для использования вашего сеанса тестирования.
Интересный вариант. Лучший способ узнать это - взглянуть на исходники Hibernate. Насколько я понимаю, сеанс
не несет особого состояния, за исключением следующего:
JDBCContext
и ActionQueue
. И последнее, откат самой транзакции никак не влияет на состояние сеанса, см. JDBCTransaction .
Насколько я понял, сеанс
действительно переживает ошибочную транзакцию, за исключением того, что кэш первого уровня может быть немного неточным; чтобы обойти это, вы можете предпочесть вызвать session.refresh
или session.load
для явной повторной синхронизации состояний.
РЕДАКТИРОВАТЬ: самый быстрый способ проверить исключения JDBC - это, вероятно, session.createSQLQuery («что-то оскорбительное для парсера SQL»). ExecuteUpdate ()
- вы получите идеальное SQLGrammarException
- и прерванная транзакция =)
Я считаю, что
Практически невозможно узнать, будет ли работать Hibernate, он столкнулся с неожиданной ситуацией и является теперь работает в неопределенном состоянии - в основном вы будете вызывать UB, выполняя какие-либо другие операции в сеансе.
Идея - зарегистрировать перехватчик и выбросить в него исключение HibernateException - надеюсь, что Hibernate его не поймает: D
Внедрение ошибки?