2010-04-02 5 views
13

В ссылке Hibernate, он несколько раз заявлял, чтоКак сломать сеанс Hibernate?

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

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

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

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

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

  1. При каких обстоятельствах сеанс Hibernate действительно стал непригодным для использования после HibernateException был брошен (Update: и каковы симптомы)?
  2. Как воспроизвести это в тесте (Обновление: желательно в интеграции, а не в модульном тесте)?
  3. (Что такое правильный термин для такого теста?)

ответ

4

При каких обстоятельствах сеанс Hibernate действительно стал непригодным для использования после HibernateException был брошен?

Интересный вопрос. Я почти уверен, что видел случаи, когда сеанс все еще «работал» после такого исключения. Проблема в том, что это не гарантировано. Мне нужно копать это немного больше.

Update: Цитирование this message от разработчика Hibernate в форумах Hibernate:

зимует сессию должен быть выброшен, когда происходит любое исключение.Его можно оставить в несогласованном состоянии относительно базы данных. Это не относится к сеансу только для чтения, поскольку он не использует кэширование на уровне сеанса. Кроме того, вы можете очистить кеш уровня сеанса при возникновении исключения (но мне лично не нравится этот подход, поскольку он не является чистым решением, и это может привести к будущим проблемам и проблемам).

Таким образом, проблема не в том, что Session «технически полезен» или нет, проблема в том, что он может не вести себя так, как ожидалось. И вы явно этого не хотите.

Как воспроизвести это в тесте?

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

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

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

1

Мой взгляд на это, что

  1. It't рядом невозможно знать, если спящий режим будет работать, он столкнулся с непредвиденной ситуацией и в настоящее время работает в неопределенном состоянии - в основном вы будете вызывать UB путем выполнения каких-либо операций в сеансе.

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

  3. Fault?

+0

Что касается 1), это тоже мое понимание - так что я счастлив, что сделал наше приложение более надежным. Прямая проблема заключается в том, как проверить это в независимом тесте? 2) звучит интересно, так как это можно было бы сделать без изменения самого приложения. –

3

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

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

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

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

EDIT: самый быстрый способ проверить исключения JDBC, вероятно session.createSQLQuery("something offensive to SQL parser").executeUpdate() - вы получите идеальный SQLGrammarException - и сломанная сделка =)

0

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

+0

Это действительно исключает исключение HibernateException, но оно не влияет на состояние сеанса Hibernate. Другими словами, это всего лишь манекен, выполненный с помощью mock Session. –

+0

Возможно, я не понимаю, что вы ищете. вы ищете надежный способ перевести спящий режим в разбитое (например, неопределенное) состояние? и что потом? – james

+0

Я ищу надежный способ перевести сеанс Hibernate в состояние разбитое, чтобы сбой старой версии нашего приложения (который повторяет один и тот же сеанс транзакций), и более новую версию (которая получает новый сеанс для каждой транзакции) проходит тест. –

Смежные вопросы