Hibernate org.hibernate.LazyInitializationException: Failed to lazily initialize the role collection:

I have the following Entity classes, when I run my application, I get the following exception. Some of these other issues do not solve the problem.

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) 

How can I solve this problem?

Emp Entity

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

Depth entity

 @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(); } 

RESTful Jersey Service

  @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> 
+6
source share
3 answers

I solved the problem by adding the following to 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> 

courtesy here and here

thanks

+9
source

The problem is that the database transaction / JPA scope contains only the service (which I assume is a non-bean session) and does NOT contain a REST bean resource.

  • Web server sends request to JAX-RS service
  • JAX-RS service initiates an EJB Bean inactivity session
  • Transaction Start
  • An EJB Bean non-authoritative session is loading data from a database (other beans may be involved)
  • Unauthorized EJB Bean Session Returns Result
  • Transaction Ends
  • JAX-RS service returns result
  • JAX-RS Producer creates XML from a List<Emp> and accesses the empDeptno field.

So, when Jersey gets an Emp list to output XML from it, the transaction is already closed. When the empDeptno field now moves, the JPA tries to lazily load it, which fails because we are already out of a valid transaction / session.

You can try to expand the scope of the transaction to also contain the Jersey Bean REST resource by making it a session without a Bean state. Then it could be as follows:

  • Web server sends request to JAX-RS service
  • Transaction Start
  • JAX-RS service initiates an EJB Bean inactivity session
  • An EJB Bean non-authoritative session is loading data from a database (other beans may be involved)
  • Unauthorized EJB Bean Session Returns Result
  • JAX-RS service returns result
  • JAX-RS Producer creates XML from a List<Emp> and accesses the empDeptno field.
  • Transaction Ends

I am not 100% sure, it is also possible that step 8 comes before step 7, so the transaction can be closed before the manufacturer completes its work. If this is the case, this decision is simply wrong ...

But I think you just need to try ...

+5
source

If you want to continue using FetchType.LAZY , but to access lazy loading attributes for some queries, you will need a portable solution to access the field and perform an operation on it while it is still in the transaction / session. I mention portability because AFAIK Hibernate offers at least one other approach to explicitly launch a download, which is not part of the JPA specification.

Adapting the code, it might look like this:

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

EDIT: Another portable alternative would be to use fetch joins in the request. Your Emp.findAllEmployees request might look like this:

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

Make it a left join if you have Emps without departments and departments without empDetNo

+2
source

Source: https://habr.com/ru/post/958696/


All Articles