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
하면 트랜잭션 전파와 같은 많은 중요한 측면이 자동으로 처리됩니다. 이 경우 다른 트랜잭션 방법을 호출하면 "세션 없음"예외를 피하면서 진행중인 트랜잭션에 참여할 수 있습니다.
당신은 설정하려고 할 수 있습니다
<property name="hibernate.enable_lazy_load_no_trans">true</property>
hibernate.cfg.xml 또는 persistence.xml에서
이 속성에서 명심해야 할 문제는 여기에 잘 설명되어 있습니다.
를 처리하는 가장 좋은 방법LazyInitializationException
은 JOIN 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)
호출 할 때이 예외 session.getEntityById()
는 세션이 닫힙니다. 따라서 엔터티를 세션에 다시 연결해야합니다. 또는 쉬운 솔루션은 구성이다 default-lazy="false"
당신에 entity.hbm.xml
또는 주석을 사용하는 경우 만 추가 @Proxy(lazy=false)
엔터티 클래스.
스프링 데이터 jpa, 스프링 부트를 사용하는 경우 application.properties에이 행을 추가 할 수 있습니다
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
같은 문제가 발생했습니다. 이 문제를 해결하는 또 다른 방법은 다음과 같이 모델에서 요소를 가져 오기 위해 쿼리를 변경할 수 있다는 것입니다.
Query query = session.createQuery("from Model m join fetch m.element where modelGroup.id = :modelGroupId")
이 오류를 광범위하게 처리하는 몇 가지 좋은 답변이 있습니다. 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.
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.
If you are using JPQL, use JOIN FETCH is the easiest way: http://www.objectdb.com/java/jpa/query/jpql/from#LEFT_OUTER_INNER_JOIN_FETCH_
This means that the object which you are trying to access is not loaded, so write a query that makes a join fetch of the object which you are trying to access.
Eg:
If you are trying to get ObjectB from ObjectA where ObjectB is a foreign key in ObjectA.
Query :
SELECT objA FROM ObjectA obj JOIN FETCH obj.objectB objB
If you are using Grail's
Framework, it's simple to resolve lazy initialization exception by using Lazy
keyword on specific field in Domain Class.
For-example:
class Book {
static belongsTo = [author: Author]
static mapping = {
author lazy: false
}
}
Find further information here
This means you are using JPA or hibernate in your code and performing modifying operation on DB without making the business logic transaction. So simple solution for this is mark your piece of code @Transactional
Thanks.
In my case a misplaced session.clear()
was causing this problem.
Faced the same Exception in different use case.
Use Case : Try to read data from DB with DTO projection.
Solution: Use get method instead of load.
Generic Operation
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;
}
}
Persistence Class
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
}
CustomerDAO interface
public interface CustomerDAO
{
public CustomerTO getCustomerById(int cid);
}
Entity Transfer Object Class
public class CustomerTO {
private int customerId;
private String customerName;
private String city;
//constructors , setters and getters
}
Factory Class
public class DAOFactory {
static CustomerDAO customerDAO;
static {
customerDAO = new HibernateCustomerDAO();
}
public static CustomerDAO getCustomerDAO() {
return customerDAO;
}
}
Entity specific 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;
}
}
Retrieving data: Test Class
CustomerDAO cdao = DAOFactory.getCustomerDAO();
CustomerTO c1 = cdao.getCustomerById(2);
System.out.println("CustomerName -> " + c1.getCustomerName() + " ,CustomerCity -> " + c1.getCity());
Present Data
Query and output generated by Hibernate System
Hibernate: select customer0_.Id as Id1_0_0_, customer0_.City as City2_0_0_, customer0_.Name as Name3_0_0_ from CustomerLab31 customer0_ where customer0_.Id=?
CustomerName -> Cody ,CustomerCity -> LA
uses session.get(*.class, id); but do not load function
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
Do the following changes in 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>
'programing tip' 카테고리의 다른 글
Go를 사용하여 JSON을 예쁘게 인쇄하려면 어떻게해야합니까? (0) | 2020.06.06 |
---|---|
모듈을 만들 수 없습니다 : 관련 gradle 구성을 찾을 수 없습니다. (0) | 2020.06.06 |
org.hibernate.LazyInitializationException 수정하는 방법-프록시를 초기화 할 수 없습니다-세션 없음 (0) | 2020.06.06 |
HTML 텍스트 오버플로 줄임표 감지 (0) | 2020.06.06 |
문자열을 Uri로 변환 (0) | 2020.06.06 |