首页 文章

org.hibernate.LazyInitializationException - 无法初始化代理 - 没有会话

提问于
浏览
123

我得到以下异常:

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)

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

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);
            @SuppressWarnings("unchecked")
            List<Model> modelList = (List<Model>)query.list(); 
            Model model = null;
            // Cerco il primo Model che è in esercizio: idwf_model_type = 3
            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);
            @SuppressWarnings("unchecked")
            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但我不允许这样做,这就是为什么我被建议控制会话

17 回答

  • 95

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

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

    在您的配置中 .

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

    Hibernate.initialize(subProcessModel.getElement());
    

    当你还在活跃的会话中 .

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

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

    请注意这个代码只是在查询语句中过滤那些类型id等于3的模型,只需要几行 .

    更多阅读:

    session factory configuration

    problem with closed session

  • 34

    你可以尝试设置

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

    在hibernate.cfg.xml或persistence.xml中

    要记住这个属性的问题很好解释here

  • 1

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

    @Transactional
    public class My Class {
        ...
    }
    

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

  • -3

    The best way to handle the LazyInitializationException是使用 JOIN FETCH 指令:

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

    无论如何,不要使用以下一些答案所建议的反模式:

    有时,DTO projection是比获取实体更好的选择,这样,你就不会得到任何 LazyInitializationException .

  • 7

    对于下面的注释,我得到了一对多关系的相同错误 .

    @OneToMany(mappedBy="department", cascade = CascadeType.ALL)
    

    添加fetch = FetchType.EAGER后更改如下,它对我有用 .

    @OneToMany(mappedBy="department", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
    
  • -3

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

  • 75

    如果你使用spring data jpa,spring boot你可以在application.properties中添加这一行

    spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
    
  • 0

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

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

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

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

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

  • 0

    如果您使用的是JPQL,请使用JOIN FETCH是最简单的方法:http://www.objectdb.com/java/jpa/query/jpql/from#LEFT_OUTER_INNER_JOIN_FETCH_

  • 5

    如果您使用的是 Grail's Framework,则可以通过在Domain Class中的特定字段上使用 Lazy 关键字来解决延迟初始化异常 .

    例如:

    class Book {
        static belongsTo = [author: Author]
        static mapping = {
            author lazy: false
        }
    }
    

    查找更多信息here

  • 5

    这意味着您尝试访问的对象未加载,因此请编写一个查询,该查询将生成您尝试访问的对象的 join fetch .

    例如:

    如果您尝试从ObjectA获取ObjectB,其中ObjectB是ObjectA中的外键 .

    查询:

    SELECT objA FROM ObjectA obj JOIN FETCH obj.objectB objB
    
  • 4

    这意味着您在代码中使用JPA或hibernate,并在不执行业务逻辑事务的情况下对DB执行修改操作 . 对此的简单解决方案是标记您的代码@Transactional

    谢谢 .

  • -1

    在我的情况下,错误的 session.clear() 导致了这个问题 .

  • 0

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

  • 2

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

  • 0

    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>
    

相关问题