Pregunta

I'm using Spring with JPA and Hibernate. I've got some DAO-Classes that are annotated with @Repositoy and some Controller-Classes. When I call one of the dao's methods in my controller to load some entities I get back the Entity and after that, I want to get some other entities that are stored in a field of the first loaded entity. But at that time spring has already closed the session and lazy loading is no longer possible.

My db.xml configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd  
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/data/jpa
        http://www.springframework.org/schema/data/jpa/spring-jpa.xsd" default-autowire="byName">

    <!-- Scans within the base package of the application for @Components to configure as beans -->
    <bean id="placeholderConfig"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:db.properties" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!-- <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="jpaVendorAdapter" />
    </bean> -->
    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true" />
                <property name="generateDdl" value="true" />
                <property name="databasePlatform" value="${db.dialect}" />
            </bean>
        </property>     
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="${db.driver}" />
        <property name="url" value="${db.url}" />
        <property name="username" value="${db.username}" />
        <property name="password" value="${db.password}" />
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" />
</beans>

The method in the Dao is annotated as follows:

@Transactional(readOnly = true, propagation=Propagation.REQUIRED)

now I wanna do something like this:

@Controller
public class HomeController{

    @Autowired
    private UserDao userDao;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ResponseEntity<String> home(){
        ...
        User user = userDao.findUser(id);
        Set<Order> orders = user.getOrders();
        ...
    String myResult = ...;
    return jsonService.generateResponse(myResult);
    }

}

@Repository
public class UserDao{

    @PersistenceContext
    private EntityManager entityManager;

    public User findUser(Integer id){
        return entityManager.find(User.class, id);
    }
}

The set of orders should be lazy-loaded but i get the following exception: org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:...,no session or session was closed

root cause: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: ..., no session or session was closed

I tried to annotate the method in Controller wirt @Transactional and also to set mode="aspectj" in annotation-driven property in the db.xml, but nothing did work. Is there any way to lazy load the orders of the user?

For any help, thanking you in anticipation!

¿Fue útil?

Solución

You can use special filter to get session in web view. Add to your web.xml

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

the filter works as follows:

  • The filter intercepts a servlet request
  • The filter opens an EntityManager and binds it to the current thread
  • Web controller is called
  • Web controller calls service
  • Transaction interceptor begins a new transaction, retrieves the thread-bound EntityManager and binds it to the transaction
  • Service is called, does some stuff with EntityManager, then returns
  • Transaction interceptor flushes the EntityManager then commits the transaction
  • Web controller prepares view, then returns
  • View is built
  • Filter closes the EntityManager and unbinds it from current thread
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top