我可以在事务外部停用Hibernate以避免LazyInitializationException

时间:2013-05-27 08:55:46

标签: hibernate jpa

编辑 - 我使用库https://github.com/FasterXML/jackson-module-hibernate解决了我对jackson / hibernate的具体问题。解决方案不是我在这里搜索的解决方案,但在我的情况下它同样有效。

原始问题:

我最近在使用Hibernate / Spring / Jackson时遇到了臭名昭着的org.hibernate.LazyInitializationException。我遇到的问题是当jackson尝试序列化和对象时,发现一个属性是一个懒惰的值并且轮胎访问它。我已经阅读了很多关于此的问题,帖子和讨论,但建议的解决方案似乎总是两种选择的变体

  • 确保在事务结束前加载了延迟属性。
  • 配置jackson忽略该属性。

我想知道是否还有其他解决方案,因为事实是当我的服务返回一个Hibernate对象时,某些属性未初始化,那么我想以这种方式显示对象。为特定目的配置jackson似乎是一种策略,其中表示层需要复杂的数据库层知识,这似乎是一个糟糕的解决方案。

我希望它从我最初的框架开始工作的方式是,无论何时在事务外部访问Hibernate实体,hibernate都不应该关心对象,它应该像普通的POJO一样工作。实质上:

  1. 开始交易
  2. 对Hibernate托管对象执行CRUD操作。
  3. 结束事务并可能返回已读取/已更改的已获取/已修改对象,而不会将事件传播到基础数据库。
  4. 所需行为的示例:

    //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。

    关于这个的两个问题:

    • 可以像我描述的那样或以类似的方式完成吗?
    • 这是好事还是坏事?

3 个答案:

答案 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();