Java 如何修复 org.hibernate.LazyInitializationException - 无法初始化代理 - 没有会话

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21574236/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 09:26:28  来源:igfitidea点击:

How to fix org.hibernate.LazyInitializationException - could not initialize proxy - no Session

javahibernatesessionormlazy-loading

提问by Blerta Dhimitri

I get the following exception:

我收到以下异常:

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)

when I try to call from main the following lines:

当我尝试从 main 调用以下几行时:

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

I implemented the getModelByModelGroup(int modelgroupid)method firstly like this :

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;
    }
}

and got the exception. Then a friend suggested me to always test the session and get the current session to avoid this error. So I did this:

并得到了例外。然后一个朋友建议我总是测试会话并获取当前会话以避免此错误。所以我这样做了:

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;        
        }
    }
}

but still, get the same error. I have been reading a lot for this error and found some possible solutions. One of them was to set lazyLoad to false but I am not allowed to do this that's why I was suggested to control the session

但仍然得到同样的错误。我已经阅读了很多关于这个错误的信息,并找到了一些可能的解决方案。其中之一是将 lazyLoad 设置为 false,但我不允许这样做,这就是为什么我被建议控制会话的原因

采纳答案by goroncy

What is wrong here is that your session management configuration is set to close session when you commit transaction. Check if you have something like:

这里的错误是您的会话管理配置设置为在您提交事务时关闭会话。检查你是否有类似的东西:

<property name="current_session_context_class">thread</property>

in your configuration.

在您的配置中。

In order to overcome this problem you could change the configuration of session factory or open another session and only than ask for those lazy loaded objects. But what I would suggest here is to initialize this lazy collection in getModelByModelGroup itself and call:

为了克服这个问题,您可以更改会话工厂的配置或打开另一个会话,并且只要求那些延迟加载的对象。但是我在这里建议的是在 getModelByModelGroup 本身中初始化这个惰性集合并调用:

Hibernate.initialize(subProcessModel.getElement());

when you are still in active session.

当您仍在活动会话中时。

And one last thing. A friendly advice. You have something like this in your method:

还有最后一件事。一个友好的建议。你的方法中有这样的东西:

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

Please insted of this code just filter those models with type id equal to 3 in the query statement just couple of lines above.

请插入此代码,只需在上面几行的查询语句中过滤那些类型 id 等于 3 的模型。

Some more reading:

更多阅读:

session factory configuration

会话工厂配置

problem with closed session

关闭会话的问题

回答by Sandeep Roniyaar

you could also solved it by adding lazy=false into into your *.hbm.xml file or you can init your object in Hibernate.init(Object) when you get object from db

您也可以通过将 lazy=false 添加到 *.hbm.xml 文件中来解决它,或者当您从 db 获取对象时,您可以在 Hibernate.init(Object) 中初始化您的对象

回答by Wilianto Indrawan

You can try to set

你可以尝试设置

<property name="hibernate.enable_lazy_load_no_trans">true</property>

in hibernate.cfg.xml or persistence.xml

在 hibernate.cfg.xml 或 persistence.xml 中

The problem to keep in mind with this property are well explained here

这个属性要记住的问题在这里有很好的解释

回答by Tony Vu

I encountered the same issue. I think another way to fix this is that you can change the query to join fetch your Element from Model as follows:

我遇到了同样的问题。我认为解决此问题的另一种方法是您可以更改查询以加入从模型中获取您的元素,如下所示:

Query query = session.createQuery("from Model m join fetch m.element where modelGroup.id = :modelGroupId")

回答by Artavazd Manukyan

uses session.get(*.class, id); but do not load function

使用 session.get(*.class, id); 但不加载功能

回答by user2601995

If you using Spring mark the class as @Transactional, then Spring will handle session management.

如果您使用 Spring 将该类标记为@Transactional,则 Spring 将处理会话管理。

@Transactional
public class MyClass {
    ...
}

By using @Transactional, many important aspects such as transaction propagation are handled automatically. In this case if another transactional method is called the method will have the option of joining the ongoing transaction avoiding the "no session" exception.

通过使用@Transactional,可以自动处理许多重要方面,例如事务传播。在这种情况下,如果调用另一个事务方法,该方法将可以选择加入正在进行的事务,避免“无会话”异常。

WARNINGIf you do use @Transactional, please be aware of the resulting behavior. See this articlefor common pitfalls. For example, updates to entities are persisted even ifyou don't explicitly call save

警告如果您确实使用了@Transactional,请注意由此产生的行为。请参阅这篇文章了解常见的陷阱。例如,即使您没有显式调用,对实体的更新也会被持久化save

回答by Night Owl

There are several good answers here that handle this error in a broad scope. I ran into a specific situation with Spring Security which had a quick, although probably not optimal, fix.

这里有几个很好的答案可以在广泛的范围内处理这个错误。我遇到了 Spring Security 的一个特定情况,它有一个快速但可能不是最佳的修复。

During user authorization (immediately after logging in and passing authentication) I was testing a user entity for a specific authority in a custom class that extends SimpleUrlAuthenticationSuccessHandler.

在用户授权期间(在登录并通过身份验证后立即),我在扩展 SimpleUrlAuthenticationSuccessHandler 的自定义类中测试用户实体的特定权限。

My user entity implements UserDetails and has a Set of lazy loaded Roles which threw the "org.hibernate.LazyInitializationException - could not initialize proxy - no Session" exception. Changing that Set from "fetch=FetchType.LAZY" to "fetch=FetchType.EAGER" fixed this for me.

我的用户实体实现了 UserDetails 并且有一组延迟加载的角色,它抛出了“org.hibernate.LazyInitializationException - 无法初始化代理 - 没有会话”异常。将该 Set 从“fetch=FetchType.LAZY”更改为“fetch=FetchType.EAGER”为我解决了这个问题。

回答by ArunDhwaj IIITH

Do the following changes in servlet-context.xml

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>

回答by Reddeiah Pidugu

This exception because of when you call session.getEntityById(), the session will be closed. So you need to re-attach the entity to the session. Or Easy solution is just configure default-lazy="false"to your entity.hbm.xmlor if you are using annotations just add @Proxy(lazy=false)to your entity class.

这个异常是因为当你调用时session.getEntityById(),会话将被关闭。因此,您需要将实体重新附加到会话中。或者简单的解决方案只是配置default-lazy="false"到您的entity.hbm.xml或者如果您正在使用注释,只需添加@Proxy(lazy=false)到您的实体类。

回答by Vlad Mihalcea

The best way to handle the LazyInitializationExceptionis to use the JOIN FETCHdirective:

处理 的最佳方法LazyInitializationException是使用JOIN FETCH指令:

Query query = session.createQuery(
    "from Model m " +
    "join fetch m.modelType " +
    "where modelGroup.id = :modelGroupId"
);

Anyway, DO NOT use the following Anti-Patterns as suggested by some of the answers:

无论如何,不​​要按照某些答案的建议使用以下反模式:

Sometimes, a DTO projectionis a better choice than fetching entities, and this way, you won't get any LazyInitializationException.

有时,DTO 投影是比获取实体更好的选择,这样,您将不会获得任何LazyInitializationException.