Как повредить Быть в спящем режиме сессию?

В Быть в спящем режиме ссылке это несколько раз указывается это

Все исключения, выданные, в спящем режиме, являются фатальными. Это означает, что необходимо откатывать транзакцию базы данных и закрыть ток Session. Нельзя продолжить работать с a Session это выдало исключение.

Одно из наших приложений прежней версии использует единственную сессию для обновления/вставления многих записей из файлов в Таблицу базы данных. Каждая запись обновляет/вставляет, сделан в отдельной транзакции, которая затем фиксируется (или откатывается в случае, если ошибка произошла). Затем для следующей записи новая транзакция открыта и так далее. Но та же сессия используется в течение целого процесса, даже если a HibernateException был пойман посреди обработки. Мы используем Oracle 9i btw с, в спящем режиме 3.24.sp1 на JBoss 4.2.

Читая вышеупомянутое в книге, я понял, что этот дизайн может перестать работать. Таким образом, я осуществил рефакторинг приложение для использования отдельной сессии для каждого рекордного обновления. В модульном тесте с ложной фабрикой сессии я могу проверить, что это теперь запрашивает новую сессию на каждое рекордное обновление.Пока все хорошо.

Однако мы не нашли способа воспроизвести отказ сессии при тестировании целого приложения (это будет стресс-тестом btw, или...?). Мы думали о закрытии слушателя DB, но мы поняли, что приложение сохраняет набор соединений открытым для DB, и слушатель не влиял бы на те соединения. (Это - веб-приложение, активированное один раз в ночь планировщиком, но это может также быть активировано через браузер.) Затем мы пытались уничтожить некоторые из тех соединений в DB, в то время как приложение обрабатывало обновления - это привело к некоторым неудавшимся обновлениям, но затем приложение счастливо продолжало обновлять остальную часть записей. По-видимому, Будьте в спящем режиме, достаточно умно для повторного открытия поврежденных соединений под капотом, не повреждая целую сессию.

Таким образом, это не могло бы быть критической проблемой, в конце концов, поскольку наше приложение, кажется, достаточно устойчиво даже в его исходной форме. Однако проблема продолжает прослушивать меня. Я хотел бы знать:

  1. При каких обстоятельствах делает Быть в спящем режиме сессию, действительно становятся неприменимыми после a HibernateException был брошен (Обновление: и каковы признаки)?
  2. Как воспроизвести это в тесте (Обновление: предпочтительно в интеграции, а не модульном тесте)?
  3. (Каков надлежащий термин для такого теста?)
13
задан Péter Török 2 April 2010 в 11:09
поделиться

4 ответа

При каких обстоятельствах сеанс 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 . Итак, вместо того, чтобы что-то доказывать, я полагаю, что правильнее всего следовать рекомендации (или предлагаемой альтернативе, но я бы просто запросил новую сессию и закрыть его для каждой транзакции, независимо от того, возникло ли исключение).

Какой термин подходит для такого теста?

Интеграционный тест? Тест на устойчивость?

4
ответ дан 2 December 2019 в 01:41
поделиться

Создайте подкласс сеанса для тестирования. Реализуйте его, чтобы генерировать исключение в каком-то конкретном сценарии. Используйте тестовую конфигурацию гибернации, которая настраивает спящий режим для использования вашего сеанса тестирования.

0
ответ дан 2 December 2019 в 01:41
поделиться

Интересный вариант. Лучший способ узнать это - взглянуть на исходники Hibernate. Насколько я понимаю, сеанс не несет особого состояния, за исключением следующего:

  • кеш первого уровня (см. StatefulPersistenceContext ) - это может быть фактически сломан после сбоя транзакции;
  • очередь действий (см. ActionQueue ) - кажется, все в порядке, если вы выполняете очистку вручную;
  • прослушиватели событий - их экземпляры знают о сеансе (см. EventSource ) и, как вы могли заметить, исключения JDBC всегда вызываются сбросом ( DefaultFlushEventListener , если быть более точным), но беглый взгляд на AbstractFlushingEventListener показывает что они действительно работают с сеансами JDBCContext и ActionQueue .

И последнее, откат самой транзакции никак не влияет на состояние сеанса, см. JDBCTransaction .

Насколько я понял, сеанс действительно переживает ошибочную транзакцию, за исключением того, что кэш первого уровня может быть немного неточным; чтобы обойти это, вы можете предпочесть вызвать session.refresh или session.load для явной повторной синхронизации состояний.

РЕДАКТИРОВАТЬ: самый быстрый способ проверить исключения JDBC - это, вероятно, session.createSQLQuery («что-то оскорбительное для парсера SQL»). ExecuteUpdate () - вы получите идеальное SQLGrammarException - и прерванная транзакция =)

3
ответ дан 2 December 2019 в 01:41
поделиться

Я считаю, что

  1. Практически невозможно узнать, будет ли работать Hibernate, он столкнулся с неожиданной ситуацией и является теперь работает в неопределенном состоянии - в основном вы будете вызывать UB, выполняя какие-либо другие операции в сеансе.

  2. Идея - зарегистрировать перехватчик и выбросить в него исключение HibernateException - надеюсь, что Hibernate его не поймает: D

  3. Внедрение ошибки?

1
ответ дан 2 December 2019 в 01:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: