【问题标题】:LazyInitializationException for some of requests某些请求的 LazyInitializationException
【发布时间】:2023-03-16 06:50:01
【问题描述】:

这可能是重复的,但我这几天一直在努力解决这个问题。经过几十个教程、书籍、堆栈答案等,我陷入了死胡同。

这是 RESTfull Spring 休眠应用程序

  1. 如何消除懒惰初始化异常和Session问题?我试图在模型类中设置 Eager fetch,但它对我不起作用,我有 Transaction 注释,但它仍然是一样的。我敢打赌它必须在 Spring xml 配置中以某种方式设置,但不知道该怎么做。
  2. 为什么 ... /getAllCountries 工作得非常好,而 /getCountry/id 会抛出会话错误?我看不出它们之间有什么区别。
  3. 请给我一个基于代码的答案。

控制器:

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

        // .....    
    }

道:

@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...
}

弹簧配置 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>

【问题讨论】:

    标签: spring hibernate rest


    【解决方案1】:

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

    休眠文档:

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

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

    对你来说,这意味着它在 Spring 尝试编组对象时初始化,也就是 Session 关闭时。

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

    或者在Session还在的时候手动触发延迟加载,就像调用对象的任意成员一样(比如在集合上调用List.size()来强制加载)。

    【讨论】:

    • 你成就了我的一天。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2010-09-21
    • 2014-12-09
    • 1970-01-01
    • 2014-11-10
    • 1970-01-01
    • 2012-08-24
    • 2013-08-06
    • 1970-01-01
    相关资源
    最近更新 更多