原始问题:
我最近在使用Hibernate / Spring / Jackson时遇到了臭名昭着的org.hibernate.LazyInitializationException
。我遇到的问题是当jackson尝试序列化和对象时,发现一个属性是一个懒惰的值并且轮胎访问它。我已经阅读了很多关于此的问题,帖子和讨论,但建议的解决方案似乎总是两种选择的变体
我想知道是否还有其他解决方案,因为事实是当我的服务返回一个Hibernate对象时,某些属性未初始化,那么我想以这种方式显示对象。为特定目的配置jackson似乎是一种策略,其中表示层需要复杂的数据库层知识,这似乎是一个糟糕的解决方案。
我希望它从我最初的框架开始工作的方式是,无论何时在事务外部访问Hibernate实体,hibernate都不应该关心对象,它应该像普通的POJO一样工作。实质上:
所需行为的示例:
//Start transaction
MyEntity entity = entityManager.find(primaryKey, MyEntity.class);
entity.getLazyLoadedFooList(); //Load the list from database
//End transaction
entity.getLazyLoadedBarList(); //Return null instead of throw LazyInitializationException
基本思想是应用程序具有表示,服务和DAO层。 DAO层涉及针对数据库的CRUD操作。 Service层在事务中包装DAO方法,并返回表示所请求数据的java对象。然后,这些对象可用于表示层,它将 转换为所需的格式,在本例中为JSON。
关于这个的两个问题:
答案 0 :(得分:0)
获取实体后,您可以从休眠会话中detach
获取该实体。
之后你不会得到任何LazyInitializationException
(但是懒惰的字段将为空)。
所以按照你的例子:
//Start transaction
MyEntity entity = entityManager.find(primaryKey, MyEntity.class);
entity.getLazyLoadedFooList(); //Load the list from database
//End transaction
entityManager.clear(); // detaches the enitities
entity.getLazyLoadedBarList(); //Return null instead of throw LazyInitializationException
答案 1 :(得分:0)
您可以尝试以下代码将实体从休眠实体更改为常规POJO。我使用它来读取我的代码中存在的类的注释,而不是在hibernate代理中。
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.Hibernate;
import org.hibernate.proxy.HibernateProxy;
public class StripHibernateProxy {
// This function takes the hibernate entity and forces it to be a real java
// object instead
@SuppressWarnings("unchecked")
public static <T> T initializeAndUnproxy(T entity) {
if (entity == null) {
throw new NullPointerException("Entity passed for initialization is null");
}
Hibernate.initialize(entity);
if (entity instanceof HibernateProxy) {
entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
}
return entity;
}
}
答案 2 :(得分:0)
这个问题真的有答案吗?多年来我一直沉迷于它,只发现了一些像Gilead或Jackson-hibernate模块这样的黑客解决方案。如果hibernate会尊重POJO合约并且不抛出异常会很好,至少如果它被设置为这样做。也许某种类似于只读的提示。
List<Customer> list = em.createQuery(q, Customer.class)
.setParameter("lastName", "Vest")
.setHint("org.hibernate.readOnly", true)
.getResultList();