Конфигурация стратегии параллелизма для JBoss TreeCache в качестве кэша Hibernate 2-го уровня - PullRequest
4 голосов
/ 15 февраля 2011

Я использую JBoss EAP 4.3.

В настоящее время я изучаю различные варианты стратегии параллелизма при использовании встроенного JBoss TreeCache в качестве кэша второго уровня для Hibernate. Я настроил его и проверил, работает ли кеш, просматривая журналы, но я не уверен, какая стратегия параллелизма действительно используется и как она должна работать.

Для каждой сущности я могу установить одно из следующих значений «использования» в аннотации @Cache: NONE, READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL.

С другой стороны, в моем файле конфигурации JBossTreeCache я могу установить для IsolationLevel одно из следующих значений для всего кэша: NONE, READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE (или просто используйте OPTIMISTIC).

При просмотре параметров конфигурации по одному документация достаточно ясна, но мне интересно, что произойдет, когда вы объедините различные параметры.

Например, если вы установите @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) для сущности, но сконфигурируете NONE как IsolationLevel для JBossTreecache, что произойдет?

Я также считаю, что JBossTreeCache поддерживает только использование NONE, READ_ONLY и TRANSACTIONAL, но с каким IsolationLevel вам разрешено их комбинировать? А что будет, если вы используете, например, NONSTRICT_READ_WRITE?

Всего здесь должно быть 5х6 различных комбинаций, но не все из них имеют смысл ..

Кто-нибудь может мне помочь разобраться с этим?

1 Ответ

8 голосов
/ 22 февраля 2011

Уровень изоляции - сложная проблема.

Например, если вы задаете @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) для объекта, но настраиваете NONE как IsolationLevel для JBossTreecache, что произойдет?

В основном труднодоступные ошибки в работе ... Вы должны понимать, что, используя кэш для чтения и записи, вы по сути попадаете в распределенных транзакциях со всеми их "тонкостями".

Хорошо, насчет комбинаций: настройки кэша только для чтения в Hibernate следует использовать, когда ваши объекты не меняются.Например, для словаря страны.С ним следует использовать уровень параллелизма кэша NONE или READ_ONLY.

При изменении объектов в кэше следует использовать нестрогое чтение-запись, но это случается редко, а шансы для условий гонки невелики.Например, для словаря часовых поясов - часовые пояса могут иногда появляться / исчезать, но это может происходить пару раз в год.Снова, уровень параллелизма кеша NONE или READ_ONLY должен использоваться с ним.

Теперь, для более интересных комбинаций.

Transactional кеши в Hibernate НЕ безопасны, Hibernate предполагает, что обновления кеша являются транзакционными, но ничего не делает для их обеспечения.Таким образом, вы ДОЛЖНЫ использовать полноценного внешнего координатора XA (распределенных транзакций), и вы действительно действительно не хотите этого, если вы действительно не знаете, что делаете.Скорее всего, вам придется использовать полный контейнер EJB3 для поддержки XA-менеджера, хотя можно использовать внешний менеджер транзакций, такой как http://www.atomikos.com/ с простыми сервлетами + Spring.Очевидно, вам нужно использовать TRANSACTIONAL кешей с ним.

'READ_WRITE` - интересная комбинация.В этом режиме Hibernate сам работает как легкий XA-координатор, поэтому он не требует полноценного внешнего XA.Краткое описание того, как это работает:

  1. В этом режиме Hibernate сам управляет транзакциями.Все действия с БД должны быть внутри транзакции, режим автоматической фиксации не будет работать.
  2. В течение flush() (который может появляться несколько раз в течение срока действия транзакции, но обычно происходит непосредственно перед фиксацией) Hibernate проходит через сеанси ищет обновленные / вставленные / удаленные объекты.Затем эти объекты сначала сохраняются в базе данных, а затем блокируются и обновляются в кэше, поэтому одновременные транзакции не могут ни обновлять, ни читать их.
  3. Если транзакциязатем откат (явным образом или из-за какой-то ошибки) заблокированные объекты просто высвобождаются и удаляются из кэша, поэтому другие транзакции могут читать / обновлять их.
  4. Если транзакция зафиксирована успешно, заблокированные объектыпросто освобождены, и другие потоки могут читать / записывать их.

Здесь есть пара тонких моментов:

Возможное повторяемое нарушение чтения .Представьте, что у нас есть Транзакция A (tA) и Транзакция B (tB), которые начинаются одновременно, и оба загружают объект X, tA затем модифицирует этот объект, а затем tA фиксируется.Во многих базах данных, которые используют изоляцию моментальных снимков (Oracle, PostgreSQL, FireBird), если tB снова запрашивает объект X, он должен получить то же состояние объекта, что и в начале транзакции.Однако кэш READ_WRITE может нарушать это условие - там нет изоляции моментального снимка.Hibernate пытается обойти это, используя временные метки на кэшированных объектах, но в ОС с плохим разрешением таймера (15,6 мс в Windows) гарантированно пропускаются некоторые расы.

Возможные версии оптимистичных устаревших объектов - возможно получить устаревшие версии объектов, если вам очень не повезло работать в Windows, и у вас есть несколько транзакций, зафиксированных с одной и той же отметкой времени.

...