如何修复org.hibernate.LazyInitializationException - could not initialize proxy - no Session错误

283

我遇到了以下异常:

Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
    at sei.persistence.wf.entities.Element_$$_jvstc68_47.getNote(Element_$$_jvstc68_47.java)
    at JSON_to_XML.createBpmnRepresantation(JSON_to_XML.java:139)
    at JSON_to_XML.main(JSON_to_XML.java:84)

当我尝试从主函数调用以下代码时:

Model subProcessModel = getModelByModelGroup(1112);
System.out.println(subProcessModel.getElement().getNote());

我首先实现了getModelByModelGroup(int modelgroupid)方法,代码如下:

public static Model getModelByModelGroup(int modelGroupId, boolean openTransaction) {

    Session session = SessionFactoryHelper.getSessionFactory().getCurrentSession();     
    Transaction tx = null;

    if (openTransaction) {
        tx = session.getTransaction();
    }

    String responseMessage = "";

    try {
        if (openTransaction) {
            tx.begin();
        }
        Query query = session.createQuery("from Model where modelGroup.id = :modelGroupId");
        query.setParameter("modelGroupId", modelGroupId);

        List<Model> modelList = (List<Model>)query.list(); 
        Model model = null;

        for (Model m : modelList) {
            if (m.getModelType().getId() == 3) {
                model = m;
                break;
            }
        }

        if (model == null) {
            Object[] arrModels = modelList.toArray();
            if (arrModels.length == 0) {
                throw new Exception("Non esiste ");
            }

            model = (Model)arrModels[0];
        }

        if (openTransaction) {
            tx.commit();
        }

        return model;

   } catch(Exception ex) {
       if (openTransaction) {
           tx.rollback();
       }
       ex.printStackTrace();
       if (responseMessage.compareTo("") == 0) {
           responseMessage = "Error" + ex.getMessage();
       }
       return null;
    }
}

后来我遇到了异常。然后有个朋友建议我总是测试会话并获取当前会话以避免此错误。所以我这样做:

并得到了例外。后来朋友建议我始终测试会话并获取当前会话,以避免出现这种错误。于是我就这么做了:

public static Model getModelByModelGroup(int modelGroupId) {
    Session session = null;
    boolean openSession = session == null;
    Transaction tx = null;
    if (openSession) {
        session = SessionFactoryHelper.getSessionFactory().getCurrentSession(); 
        tx = session.getTransaction();
    }
    String responseMessage = "";

    try {
        if (openSession) {
            tx.begin();
        }
        Query query = session.createQuery("from Model where modelGroup.id = :modelGroupId");
        query.setParameter("modelGroupId", modelGroupId);

        List<Model> modelList = (List<Model>)query.list(); 
        Model model = null;

        for (Model m : modelList) {
            if (m.getModelType().getId() == 3) {
                model = m;
                break;
            }
        }

        if (model == null) {
            Object[] arrModels = modelList.toArray();
            if (arrModels.length == 0) {
                throw new RuntimeException("Non esiste");
            }

            model = (Model)arrModels[0];

            if (openSession) {
                tx.commit();
            }
            return model;
        } catch(RuntimeException ex) {
            if (openSession) {
                tx.rollback();
            }
            ex.printStackTrace();
            if (responseMessage.compareTo("") == 0) {
                responseMessage = "Error" + ex.getMessage();
            }
            return null;        
        }
    }
}

但是仍然会得到相同的错误。我已经阅读了很多关于这个错误的内容,并找到了一些可能的解决方案。其中一个是设置lazyLoad为false,但我不允许这样做,所以建议我控制session。

25个回答

0
所有关于添加JOIN FETCH(或left join fetch)的答案都是正确的,我只想补充一点: 如果您有转换器,请确保getAsObject子方法使用包含Join Fetch的sql中的“find”。 我花了很多时间来解决类似的问题,而问题就在转换器中。

0
TLDR: 始终将DTO(数据传输对象)进行序列化,避免返回实体对象。
问题的原因是在检索延迟加载的数据时,第一步是填充主对象,第二步是检索其代理对象中的数据。为此,需要一个打开的 Hibernate 会话。
问题出现在事务关闭后进行第二步操作时,这会导致一个 LazyInitializationException 异常。
我将在这里总结一些解决方案,并添加我的解决方法:
1. Avoid entity serialization, **instead serialize a dto**
2. Add `@JsonIgnore` to your `LAZY` attributes
3. Change `FetchType` to `EAGER`
4. Set `hibernate.enable_lazy_load_no_trans=true` 

只推荐使用第1和第2个选项,其他两个选项不适用于序列化阶段。因为它们在这里会带来巨大的性能开销,它们都会对数据库进行额外的数据检索。选项4实际上为每个延迟加载对象创建了一个新的事务,所以请避免使用!
我在这个问题中的建议是强烈推荐明确地只使用第1和第2个选项,并且FetchType.EAGER只用于业务逻辑,而不是作为解决此问题的方法。

-3
servlet-context.xml 文件中进行以下更改。
    <beans:property name="hibernateProperties">
        <beans:props>

            <beans:prop key="hibernate.enable_lazy_load_no_trans">true</beans:prop>

        </beans:props>
    </beans:property>

-3

使用 session.get(*.class, id) 方法,但不要加载函数。


5
请问你能否解释一下这个吗? - newday

-3

你也可以通过在 *.hbm.xml 文件中添加 lazy=false 来解决这个问题,或者当你从数据库获取对象时,在 Hibernate.init(Object) 中初始化你的对象。


10
通常情况下,添加“lazy=false”不是一个好主意。这就是为什么默认情况下“lazy”是true的原因。 - MoienGK
OP明确表示他事先不被允许这样做。 - GingerHead

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接