[java] org.hibernate.LazyInitializationException 수정하는 방법-프록시를 초기화 할 수 없습니다-세션 없음

다음과 같은 예외가 있습니다.

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

        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로 설정하는 것이었지만 세션을 제어하도록 제안 된 이유는 이것을 허용하지 않습니다.



답변

여기서 잘못된 점은 트랜잭션을 커밋 할 때 세션 관리 구성이 세션을 닫도록 설정되어 있다는 것입니다. 다음과 같은 것이 있는지 확인하십시오.

<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 인 모델을 필터링합니다.

더 읽을 거리 :

세션 팩토리 구성

닫힌 세션 문제


답변

Spring을 사용하여 클래스를 @Transactional 로 표시하면 Spring이 세션 관리를 처리합니다.

@Transactional
public class MyClass {
    ...
}

를 사용 @Transactional하면 트랜잭션 전파와 같은 많은 중요한 측면이 자동으로 처리됩니다. 이 경우 다른 트랜잭션 방법을 호출하면 “세션 없음”예외를 피하면서 진행중인 트랜잭션에 참여할 수 있습니다.

경고를 사용하는 경우 @Transactional결과 동작에 유의하십시오. 일반적인 함정에 대해서는 이 기사 를 참조하십시오 . 예를 들어, 명시 적으로 전화하지 않아도 엔터티에 대한 업데이트가 유지 됩니다.save


답변

당신은 설정하려고 할 수 있습니다

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

hibernate.cfg.xml 또는 persistence.xml에서

이 속성에서 명심해야 할 문제는 여기에 잘 설명되어 있습니다.


답변

를 처리하는 가장 좋은 방법LazyInitializationExceptionJOIN FETCH지시문 을 사용하는 것입니다 .

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

어쨌든, 일부 답변에서 제안한 다음 안티 패턴을 사용하지 마십시오.

때로는 DTO 돌기가 가져 오는 실체보다 더 나은 선택이 될 것입니다,이 방법은, 당신은 어떤을받지 않습니다 LazyInitializationException.


답변

아래 주석에 대한 일대 다 관계에 대해 동일한 오류가 발생했습니다.

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

fetch = FetchType.EAGER를 추가 한 후 아래와 같이 변경되었습니다.

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


답변

스프링 데이터 jpa, 스프링 부트를 사용하는 경우 application.properties에이 행을 추가 할 수 있습니다

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true


답변

호출 할 때이 예외 session.getEntityById()는 세션이 닫힙니다. 따라서 엔터티를 세션에 다시 연결해야합니다. 또는 쉬운 솔루션은 구성이다 default-lazy="false" 당신에 entity.hbm.xml또는 주석을 사용하는 경우 만 추가 @Proxy(lazy=false)엔터티 클래스.