Уровень изоляции - сложная проблема.
Например, если вы задаете @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.Краткое описание того, как это работает:
- В этом режиме Hibernate сам управляет транзакциями.Все действия с БД должны быть внутри транзакции, режим автоматической фиксации не будет работать.
- В течение
flush()
(который может появляться несколько раз в течение срока действия транзакции, но обычно происходит непосредственно перед фиксацией) Hibernate проходит через сеанси ищет обновленные / вставленные / удаленные объекты.Затем эти объекты сначала сохраняются в базе данных, а затем блокируются и обновляются в кэше, поэтому одновременные транзакции не могут ни обновлять, ни читать их. - Если транзакциязатем откат (явным образом или из-за какой-то ошибки) заблокированные объекты просто высвобождаются и удаляются из кэша, поэтому другие транзакции могут читать / обновлять их.
- Если транзакция зафиксирована успешно, заблокированные объектыпросто освобождены, и другие потоки могут читать / записывать их.
Здесь есть пара тонких моментов:
Возможное повторяемое нарушение чтения .Представьте, что у нас есть Транзакция A (tA) и Транзакция B (tB), которые начинаются одновременно, и оба загружают объект X, tA затем модифицирует этот объект, а затем tA фиксируется.Во многих базах данных, которые используют изоляцию моментальных снимков (Oracle, PostgreSQL, FireBird), если tB снова запрашивает объект X, он должен получить то же состояние объекта, что и в начале транзакции.Однако кэш READ_WRITE может нарушать это условие - там нет изоляции моментального снимка.Hibernate пытается обойти это, используя временные метки на кэшированных объектах, но в ОС с плохим разрешением таймера (15,6 мс в Windows) гарантированно пропускаются некоторые расы.
Возможные версии оптимистичных устаревших объектов - возможно получить устаревшие версии объектов, если вам очень не повезло работать в Windows, и у вас есть несколько транзакций, зафиксированных с одной и той же отметкой времени.