programing

org.hibernate 수정 방법Laze Initialization(레이지 초기화)예외 - 프록시를 초기화할 수 없음 - 세션 없음

bestcode 2022. 9. 1. 23:18
반응형

org.hibernate 수정 방법Laze Initialization(레이지 초기화)예외 - 프록시를 초기화할 수 없음 - 세션 없음

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

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

그래도 같은 오류가 발생합니다.저는 이 오류에 대해 많은 것을 읽고 몇 가지 가능한 해결책을 찾아냈습니다.그 중 하나는 lazy Load를 false로 설정하는 것이었는데, 저는 이것을 할 수 없기 때문에 세션을 제어하도록 제안받았습니다.

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

@Transactional
public class MyClass {
    ...
}

「」를 사용해 .@Transactional트랜잭션 전파와 같은 많은 중요한 측면이 자동으로 처리됩니다.이 경우 다른 트랜잭션 메서드가 호출될 경우 이 메서드는 "세션 없음" 예외를 회피하고 진행 중인 트랜잭션에 참여할 수 있습니다.

경고 를 사용하는 경우@Transactional그 결과 발생하는 동작에 주의해 주세요.일반적인 함정에 대해서는, 이 문서를 참조해 주세요.예를 들어 명시적으로 호출하지 않아도 엔티티에 대한 업데이트가 유지됩니다.save

설정해 볼 수 있습니다.

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

in hibernate.cfg.xml 또는 persistence.xml 중 하나

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

여기서 문제가 되는 것은 트랜잭션을 커밋할 때 세션 관리 구성이 세션을 닫도록 설정되어 있다는 것입니다.다음과 같은 항목이 있는지 확인합니다.

<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인 모델을 필터링하십시오.

기타 정보:

세션 팩토리 컨피규레이션

비공개 세션에 관한 문제

이 문제를 해결하는 가장 좋은 방법은LazyInitializationException를 사용하는 것입니다.JOIN FETCH지시:

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

단, 몇 가지 답변에 따라 다음 안티패턴을 사용하지 마십시오.

때때로 엔티티를 가져오는 것보다 DTO 투영을 선택하는 것이 더 나을 수 있습니다.이 방법으로는 아무것도 얻을 수 없습니다.LazyInitializationException.

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

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

fetch=DetailType 추가 후 아래와 같이 변경되었습니다.간절히, 나한테는 효과가 있었어.

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

spring data jpa, spring boot을 사용하는 경우 application.properties에서 이 행을 추가할 수 있습니다.

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

이 예외는 호출 시 때문에 발생합니다.session.getEntityById()세션이 종료됩니다.따라서 엔티티를 세션에 다시 연결해야 합니다.또는 간단한 솔루션은 구성만 하면 됩니다.default-lazy="false"고객님께entity.hbm.xml또는 주석을 사용하는 경우에는 추가만 하면 됩니다.@Proxy(lazy=false)엔티티 클래스로 이동합니다.

같은 문제가 발생했습니다.이 문제를 해결하기 위한 또 다른 방법은 다음과 같이 쿼리를 변경하여 조인하고 fetch your Element from Model을 다음과 같이 가져오는 것입니다.

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

이는 액세스하려는 개체가 로드되지 않았음을 의미하므로 액세스하려는 개체의 Join을 가져오는 쿼리를 작성합니다.

예:

ObjectA에서 ObjectB를 가져오려고 할 경우 ObjectB는 ObjectA의 외부 키입니다.

쿼리:

SELECT objA FROM ObjectA obj JOIN FETCH obj.objectB objB

다른 사용 사례에서 동일한 예외에 직면했습니다.

여기에 이미지 설명 입력

사용 사례 : DTO 투영으로 DB에서 데이터를 읽어 봅니다.

솔루션:로드 대신 get 메서드를 사용합니다.

범용 조작

public class HibernateTemplate {
public static Object loadObject(Class<?> cls, Serializable s) {
    Object o = null;
    Transaction tx = null;
    try {
        Session session = HibernateUtil.getSessionFactory().openSession();
        tx = session.beginTransaction();
        o = session.load(cls, s); /*change load to get*/
        tx.commit();
        session.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return o;
}

}

지속성 클래스

public class Customer {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "Id")
private int customerId;

@Column(name = "Name")
private String customerName;

@Column(name = "City")
private String city;

//constructors , setters and getters

}

고객.DAO 인터페이스

public interface CustomerDAO 
     {
   public CustomerTO getCustomerById(int cid);
     }

엔티티 전송 오브젝트 클래스

public class CustomerTO {

private int customerId;

private String customerName;

private String city;

//constructors , setters and getters

}

팩토리 클래스

public class DAOFactory {

static CustomerDAO customerDAO;
static {
    customerDAO = new HibernateCustomerDAO();
}

public static CustomerDAO getCustomerDAO() {
    return customerDAO;
}

}

엔티티 고유의 DAO

public class HibernateCustomerDAO implements CustomerDAO {

@Override
public CustomerTO getCustomerById(int cid) {
    Customer cust = (Customer) HibernateTemplate.loadObject(Customer.class, cid);
    CustomerTO cto = new CustomerTO(cust.getCustomerId(), cust.getCustomerName(), cust.getCity());
    return cto;
}

}

데이터 검색 중:테스트 클래스

CustomerDAO cdao = DAOFactory.getCustomerDAO();
CustomerTO c1 = cdao.getCustomerById(2);
System.out.println("CustomerName -> " + c1.getCustomerName() + " ,CustomerCity -> " + c1.getCity());

데이터 표시

여기에 이미지 설명 입력

최대 절전 모드에서 생성된 쿼리 및 출력

휴지 상태: customer0_ 를 선택합니다.ID는 ID1_0_0_, customer0_입니다.City as City2_0_0_, customer0_.CustomerLab31 customer0_에서 Name3_0_0_로 이름을 지정합니다.여기서 customer0_은ID=?

님의 이름 -> Cody, Customer City -> LA

여기에서는, 이 에러를 폭넓게 취급하는 좋은 답이 몇개인가 있습니다.스프링 시큐리티와 관련된 특정 상황에 부딪혔는데, 그 상황은 아마 최적이지는 않지만 신속하게 해결되었습니다.

사용자 인가 중(로그인 후 인증 전달 직후) SimpleUrlAuthentication을 확장하는 커스텀클래스의 특정 권한에 대해 사용자 엔티티를 테스트하고 있었습니다.Success Handler.

사용자 엔티티는 User Details를 구현하고 "org.hibernate"를 슬로우한 일련의 느린 로딩된 역할을 가지고 있습니다.Laze Initialization(레이지 초기화)예외 - 프록시를 초기화할 수 없음 - 세션 없음" 예외입니다."fetch=PetchType"에서 세트 변경.LAGY"에서 "fetch=PetchType"으로 이동합니다.'열심히'가 이걸 고쳐줬어요

즉, JPA를 사용하거나 코드에서 휴지 상태를 유지하며 비즈니스 로직 트랜잭션을 수행하지 않고 DB에서 수정 작업을 수행합니다.이를 위한 간단한 솔루션은 코드 조각에 @Transactional 표시를 하는 것입니다.

JPQL을 사용하는 경우 JOIN FETCH를 사용하는 것이 가장 쉬운 방법입니다.http://www.objectdb.com/java/jpa/query/jpql/from#LEFT_OUTER_INNER_JOIN_FETCH_

「 」를 사용하고 Grail's프레임워크: 를 사용하여 느린 초기화 예외를 쉽게 해결할 수 있습니다.Lazy키워드를 지정합니다.

예:

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

자세한 내용은 이쪽

에는 잘못 알고 있습니다.session.clear()을 사용하다

봄 어플리케이션에서는 추가만 하면 됩니다.

@Transactional(readOnly = true)

를 참조해 주세요.

스프링 트랜잭션 주석 가져오기

org.springframework.transaction.information을 가져옵니다.트랜잭션

@NamedEntityGraph 를 사용합니다.Eagar fetch는 퍼포먼스를 저하시킵니다.상세한 것에 대하여는, https://thorben-janssen.com/lazyinitializationexception/ 를 참조해 주세요.

already일 this this를 사용하고 있을 때 일어난 일입니다.@Transactional(value=...)복수의 트랜잭션 매니저를 사용하고 있었습니다.

내 양식은 이미 데이터를 전송하고 있었다@JsonIgnore그래서 양식에서 보내진 데이터가 불완전했어요

원래는 안티패턴 솔루션을 사용했지만, 매우 느렸습니다.false로 설정하여 비활성화했습니다.

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=false

이 수정은 로드되지 않은 데이터가 느리게 로드된 모든 개체를 데이터베이스에서 먼저 검색하도록 하는 것이었습니다.

Optional<Object> objectDBOpt = objectRepository.findById(object.getId());

if (objectDBOpt.isEmpty()) {
    // Throw error
} else {
    Object objectFromDB = objectDBOpt.get();
}

다른해 본 에는 먼저 있는 것을 것을 입니다.@JsonIgnore데이터베이스 쿼리에서 사용 중인 속성입니다.

JOIN FETCH(또는 왼쪽 Join FETCH) 추가에 대한 모든 답변은 정확합니다.변환기가 있는 경우 getAsObject 서브가 Join Fetch에 포함된 것보다도 "find"를 사용해야 합니다.비슷한 문제를 해결하기 위해 많은 시간을 허비했고, 문제는 컨버터에 있었습니다.

session.getflash.class, id)를 사용하지만 함수를 로드하지 않습니다.

또한 lazy=false를 *.hbm.xml 파일에 추가하여 해결할 수도 있습니다.또는 db에서 객체를 가져올 때 Hibernate.init(Object)에서 객체를 초기화할 수도 있습니다.

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>

언급URL : https://stackoverflow.com/questions/21574236/how-to-fix-org-hibernate-lazyinitializationexception-could-not-initialize-prox

반응형