Исключение отложенной инициализации при загрузке объекта гибернации из ehcache

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

Моя сущность имеет некоторые свойства (объекты или связанные сущности), которые определены как FetchType.Lazy. Это что-то вроде этого,

@JoinColumn(name = "inventory_item_oid", referencedColumnName = "inventory_item_oid")
@ManyToOne(fetch = FetchType.LAZY)
private InventoryItem inventoryItem;

Следовательно, не все свойства загружены. Когда предмет инвентаря необходим, он вызывается. Этот вызов вызывает исключение LazyInitialization Exception.

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

Один из этих вызовов вызывает указанное выше исключение.

Я пришел к выводу, что с помощью длительных сеансов гибернации я могу решить эту проблему. Но это не работает, потому что мое приложение основано на запросе/ответе.

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

Я хотел бы знать, есть ли другой способ получить эти объекты, определенные как ленивые.


person Raj S    schedule 06.06.2012    source источник


Ответы (1)


Вы не должны кэшировать сущности в EHCache самостоятельно. Вместо этого вы должны настроить Hibernate на использование кеша второго уровня и использовать EHCache в качестве его реализации.

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

Еще одно огромное отличие вашего самодельного решения заключается в том, что Hibernate будет возвращать вам прикрепленные объекты. Поэтому, если вы просто вызовете cachedEntity.getNonCachedEntity(), Hibernate будет лениво загружать некэшированный объект точно так же, как если бы у вас вообще не было кеша.

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

Вызовите Hibernate.initialize(foo.getInventotyItem()) для его инициализации.

Дополнительные сведения см. в документации по Hibernate. .

person JB Nizet    schedule 06.06.2012
comment
и если доступ к этому атрибуту осуществляется после закрытия сеанса, то ленивый атрибут должен быть инициализирован до закрытия сеанса. Как я узнаю, что при первом получении этот объект будет использоваться вне сеанса?! Ваше предложение похоже на инициализацию извлеченного кэшированного объекта каждый раз, что полностью нарушает преимущество использования ленивых атрибутов. - person Simon Logic; 20.10.2017
comment
Вам не нужно инициализировать ленивые атрибуты во время извлечения. Вы должны только убедиться, что он инициализирован перед закрытием сеанса, если вы собираетесь получить к нему доступ после. Самый простой способ избежать этой проблемы — либо не обращаться к какому-либо атрибуту после закрытия сеанса (т. е. закрывать его только тогда, когда вы закончите использовать объект, используя, например, фильтр открытого сеанса в представлении), либо избегайте использования сущностей после закрытия сеанса (например, путем преобразования сущностей в DTO) - person JB Nizet; 20.10.2017
comment
Хорошо, вот тест. Я вызываю метод репозитория в первый раз, и его результат с ленивыми неинициализированными реквизитами кэшируется. Тема окончена. Из другого потока я вызываю тот же метод и получаю Lazy Exception при попытке прочитать эти реквизиты. Почему, черт возьми, мне нужно выполнять дополнительную работу (например, явно открывать сеанс) вместо того, чтобы делегировать это программному обеспечению кэширования? Может быть есть еще одно решение с конфигурацией кеша? - person Simon Logic; 21.10.2017
comment
Задайте свой вопрос с соответствующими объяснениями, соответствующим кодом, что вы ожидаете, и что вместо этого произойдет. - person JB Nizet; 21.10.2017
comment
Я не вижу различий по сравнению с текущим вопросом в целом. Автор просто не показал нам конфигурацию кеша и/или точную аннотацию для кешированных методов. Для меня очевидно, что сценарий обычный. Как заставить ehcache решить эту проблему самостоятельно без дополнительного кодирования? :) - person Simon Logic; 21.10.2017
comment
Тогда мой ответ не будет другим. - person JB Nizet; 21.10.2017