복붙노트

[SPRING] Hibernate org.hibernate.LazyInitializationException : 롤 컬렉션을 지연 적으로 초기화하지 못했습니다 :

SPRING

Hibernate org.hibernate.LazyInitializationException : 롤 컬렉션을 지연 적으로 초기화하지 못했습니다 :

아래에 언급 된 Entity 클래스가 있습니다. 응용 프로그램을 실행할 때 다음 예외가 발생합니다. 다른 유사한 질문 중 일부는 문제를 해결하지 못했습니다.

WARNING: StandardWrapperValve[jersey-serlvet]: PWC1406: Servlet.service()
for servlet jersey-serlvet threw exception
org.hibernate.LazyInitializationException: failed to lazily initialize 
a collection of role: test.entity.Dept.empDeptno, no session
or session was closed
at org.hibernate.collection.internal.AbstractPersistentCollection.
throwLazyInitializationException(AbstractPersistentCollection.java:393)
       at    org.hibernate.collection.internal.AbstractPersistentCollection.
throwLazyInitializationExceptionIfNotConnected
(AbstractPersistentCollection.java:385)
    at org.hibernate.collection.internal.AbstractPersistentCollection.
initialize(AbstractPersistentCollection.java:378) 

이 문제를 어떻게 해결할 수 있습니까?

Emp 엔터티

@Entity
@Table(name = "EMP", schema = "SCOTT"
)
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Emp.findAllEmployees", query = "select e from Emp e left 
    join fetch e.deptNo order by e.empno desc")
})
public class Emp implements java.io.Serializable {
@Id
@Column(name = "EMPNO", unique = true, nullable = false, precision = 4,
scale = 0)
private short empno;
@ManyToOne
@JoinColumn(name = "DEPTNO", referencedColumnName = "DEPTNO")
private Dept deptNo;

부서 엔티티

@Entity
@Table(name = "DEPT", schema = "SCOTT"
)
@XmlRootElement
public class Dept implements java.io.Serializable {
@Id
@Column(name = "DEPTNO", unique = true, nullable = false, precision = 2,
scale = 0)
private short deptno;
@OneToMany(fetch=FetchType.LAZY,mappedBy = "deptNo")
private Set<Emp> empDeptno;

DAOImpl

@Override
public List<Emp> findAllEmployees() {
  return getEntityManager().createNamedQuery("Emp.findAllEmployees",
 Emp.class).getResultList();
}

Jersey RESTful 서비스

 @Component
 @Path("/employee")
 public class EmployeeRestService {

 @Autowired
 EmployeeService employeeService;

 @GET
 @Produces({MediaType.APPLICATION_JSON})
 public List<Emp> getEmployees() {
 List<Emp> emp = new ArrayList<Emp>();
 emp.addAll(getEmployeeService().findAllEmployees());
 return emp;
 }

Spring applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
>
    <!-- Data Source Declaration -->    
    <bean id="DataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="jdbc/scottDS"/>   
    </bean>

    <context:component-scan base-package="net.test" />
    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
    <bean id="entityManagerFactory"
          class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="DataSource" />
        <property name="packagesToScan" value="net.test" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="false" />
                <property name="generateDdl" value="false" />
                <property name="databasePlatform" value="${jdbc.dialectClass}" />
            </bean>
        </property>
    </bean>
    <bean id="defaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" />  
    <!-- Transaction Config -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager"/>          
    <context:annotation-config/>
    <bean id="hibernateStatisticsMBean" class="org.hibernate.jmx.StatisticsService">
        <property name="statisticsEnabled" value="true" />
        <property name="sessionFactory" value="#{entityManagerFactory.sessionFactory}" />
    </bean>
</beans>

해결법

  1. ==============================

    1.나는 web.xml에 다음을 추가하여이 문제를 해결했다.

    나는 web.xml에 다음을 추가하여이 문제를 해결했다.

    <filter>
    <filter-name>OpenEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>OpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    여기와 여기에 의례

    감사

  2. ==============================

    2.문제는 데이터베이스 / JPA 트랜잭션의 범위에 서비스 (Stateless Session Bean이라고 가정 함) 만 포함하고 REST 리소스 Bean을 포함하지 않는다는 것입니다.

    문제는 데이터베이스 / JPA 트랜잭션의 범위에 서비스 (Stateless Session Bean이라고 가정 함) 만 포함하고 REST 리소스 Bean을 포함하지 않는다는 것입니다.

    따라서 Jersey가 XML을 생성하는 Emp 목록을 가져 오면 트랜잭션이 이미 닫혔습니다. 이제 empDeptNo 필드가 탐색 될 때 JPA는 느리게로드하려고 시도합니다. 이는 유효한 트랜잭션 / 세션 밖에 이미 있기 때문에 실패합니다.

    당신은 Jersey REST 리소스 빈을 포함하도록 트랜잭션 범위를 확장하려고 시도 할 수있다. 다음과 같이 될 수 있습니다 :

    나는 100 % 확신하지 못한다. 단계 8이 단계 7에 오게 될 수도 있기 때문에, 생산자가 그 일을하기 전에 거래가 종료 될 수도있다. 그렇다면이 솔루션은 단순히 잘못되었습니다 ...

    하지만 그걸 해봐야 할 것 같아.

  3. ==============================

    3.FetchType.LAZY를 계속 사용하고자하지만 일부 쿼리의 경우 지연로드 된 속성에 대한 액세스가 필요한 경우 휴대용 솔루션은 필드에 액세스하여 트랜잭션 / 세션 내에서 작업을 수행하는 것입니다. 필자는 AFAIK Hibernate가 명시 적으로 JPA 스펙의 일부가 아닌 로딩을 트리거하는 적어도 하나의 다른 접근 방식을 제공하기 때문에 이식성에 대해 언급한다.

    FetchType.LAZY를 계속 사용하고자하지만 일부 쿼리의 경우 지연로드 된 속성에 대한 액세스가 필요한 경우 휴대용 솔루션은 필드에 액세스하여 트랜잭션 / 세션 내에서 작업을 수행하는 것입니다. 필자는 AFAIK Hibernate가 명시 적으로 JPA 스펙의 일부가 아닌 로딩을 트리거하는 적어도 하나의 다른 접근 방식을 제공하기 때문에 이식성에 대해 언급한다.

    코드를 수정하면 다음과 같이 보일 수 있습니다.

    public List<Emp> findAllEmployees() {
      List<Emp> employees = getEntityManager().createNamedQuery("Emp.findAllEmployees",
        Emp.class).getResultList();
    
      //trigger loading of attributes
      for(Emp emp: employees){
        emp.getDeptNo().getEmpDetNo().size();
      }
      return employees;
    }
    

    편집 : 또 다른 휴대용 대안은 쿼리에서 페치 조인을 사용하는 것입니다. Emp.findAllEmployees 쿼리는 다음과 같을 수 있습니다.

    SELECT e FROM Emp e JOIN FETCH e.dept.empDetno
    

    empDetNo가없는 부서 및 부서가없는 Emps가있는 경우 왼쪽 결합으로 만듭니다.

  4. from https://stackoverflow.com/questions/20162077/hibernate-org-hibernate-lazyinitializationexception-failed-to-lazily-initialize by cc-by-sa and MIT license