某些请求的LazyInitializationException

时间:2017-11-16 15:01:34

标签: spring hibernate rest

这可能是重复的,但我现在几天都在努力解决这个问题。经过几十个教程,书籍,堆栈答案等等,我处于死胡同。

这是RESTfull Spring hibernate app

  1. 如何消除lazyinitializationexception和Session的问题?我试图在模型类中设置eager fetch,但它对我不起作用,我有Transaction注释但它仍然是相同的。我打赌它必须在Spring xml配置中以某种方式设置,但不知道如何做到这一点。
  2. 为什么...... / getAllCountries完全正常,/ getCountry / id会引发Session错误?我认为它们之间没有区别。
  3. 请给我一个基于代码的答案。
  4. 控制器:

        @RestController
        public class CountryController {
    
            @Autowired
            CountryService countryService;
    
            @RequestMapping(value = "/getAllCountries", method = RequestMethod.GET, headers = "Accept=application/json")
            public List<Country> getCountries() {
                List<Country> listOfCountries = countryService.getAllCountries();
                return listOfCountries;
            }
    
            @RequestMapping(value = "/getCountry/{id}", method = RequestMethod.GET, headers = "Accept=application/json")
            public Country getCountryById(@PathVariable int id) {
                return countryService.getCountry(id);
            }
    
            // .....    
        }
    

    DAO:

    @Repository
    public class CountryDAO {
    
        @Autowired
        private SessionFactory sessionFactory;
    
        public void setSessionFactory(SessionFactory sf) {
            this.sessionFactory = sf;
        }
    
        public List<Country> getAllCountries() {
             Session session = this.sessionFactory.getCurrentSession();
             List<Country> countryList = session.createQuery("from Country").list();
        return countryList;
        }
    
        public Country getCountry(int id) {
            Session session = this.sessionFactory.getCurrentSession();
            Country country = (Country) session.load(Country.class, new Integer(id));
            return country;
        }
        // ......
    }
    

    服务:

    @Service("countryService")
    public class CountryService {
    
        @Autowired
        CountryDAO countryDao;
    
        @Transactional
        public List<Country> getAllCountries() {
            return countryDao.getAllCountries();
        }
    
        @Transactional
        public Country getCountry(int id) {
            return countryDao.getCountry(id);
        }
    }
    

    实体:

    @Entity
    @Table(name="COUNTRY")
    public class Country{
    
        @Id
        @Column(name="id")
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        int id;
    
        @Column(name="countryName")
        String countryName; 
    
        @Column(name="population")
        long population;
    
        public Country() {
                super();
        }
        public Country(int i, String countryName,long population) {
            super();
            this.id = i;
            this.countryName = countryName;
            this.population=population;
        }
    
        // getters and setters...
    }
    

    Spring config xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/mvc"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
    
        <annotation-driven />
    
        <resources mapping="/resources/**" location="/resources/" />
    
        <beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
                destroy-method="close">
                <beans:property name="driverClassName" value="org.postgresql.Driver" />
                <beans:property name="url"
                        value="..." />
                <beans:property name="username" value="postgres" />
                <beans:property name="password" value="..." />
        </beans:bean>
    
        <!-- Hibernate 4 SessionFactory Bean definition -->
        <beans:bean id="hibernate4AnnotatedSessionFactory"
                class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
                <beans:property name="dataSource" ref="dataSource" />
                <beans:property name="annotatedClasses">
                        <beans:list>
                                <beans:value>org.arpit.java2blog.model.Country</beans:value>
                        </beans:list>
                </beans:property>
                <beans:property name="hibernateProperties">
                        <beans:props>
                                <beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect
                                </beans:prop>
                                <beans:prop key="hibernate.show_sql">true</beans:prop>
                        </beans:props>
                </beans:property>
        </beans:bean>
    
        <context:component-scan base-package="org.arpit.java2blog" />
    
        <tx:annotation-driven transaction-manager="transactionManager"/>
    
        <beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
                <beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
        </beans:bean>
    </beans:beans>
    

    的web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://java.sun.com/xml/ns/javaee"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        version="3.0">
        <display-name>Archetype Created Web Application</display-name>
        <servlet>
     <servlet-name>spring</servlet-name>
     <servlet-class>
      org.springframework.web.servlet.DispatcherServlet
     </servlet-class>
     <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
     <servlet-name>spring</servlet-name>
     <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    </web-app>
    

1 个答案:

答案 0 :(得分:1)

您的问题来自Session.load()方法,该方法不返回对象,而是在第一次访问非标识符属性时初始化的对象的代理。

Hibernate文档:

  

T load(Class theClass,              可序列化的id)

     

返回具有给定标识符的给定实体类的持久化实例,假设是   实例存在。此方法可能返回一个代理实例   当访问非标识符方法时,按需初始化。

对于你而言,这意味着当Spring试图对该对象进行编组时会初始化它,即会话结束时。

要修复它,您可以在类级别添加@org.hibernate.annotations.Proxy(lazy = false),在dao中使用Session.get()而不是Session.load()来获取完全加载的对象(取决于成员的惰性策略) )。

或者,当Session仍然是通过调用对象的任何成员(比如在集合上调用List.size()来强制加载)时手动触发延迟加载。