【问题标题】:Hibernate many to one eager fetching not working休眠多对一急切无法正常工作
【发布时间】:2015-04-09 09:36:47
【问题描述】:

我正在尝试使用休眠注释从数据库中获取数据,但它没有按我的预期工作。我有两个表员工和部门。 java代码如下:

员工类

 @Entity
    @Table(name = "EMPLOYEE")        
    public class EmployeeBO {

        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        @Column(name = "EMPID")
        private int empId;
        @Column(name = "EMPNAME")
        private String empName;
        @Column(name = "SALARY")
        private int empSalary;
        @Column(name = "EMPADDRESS")
        private String empAddress;
        @Column(name = "EMPAGE")
        private int empAge;
        @Column(name = "DEPTID")
        private Integer deptId; 
        @ManyToOne(fetch=FetchType.EAGER)
        @JoinColumn(name="DEPTID", nullable = true, insertable = false, updatable = false)
        private DepartmentBO departmentBO;
// getter and setter 
    }

部门类:

@Entity
@Table(name = "DEPARTMENT")
public class DepartmentBO {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "DEPTID")
    private int deptid;

    @Column(name = "DEPTNAME")
    private String deptName;
   // getter and setter.
}

spring-servlet.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<!--?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" 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/context http://www.springframework.org/schema/context/spring-context-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/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">


    <context:annotation-config></context:annotation-config>

    <context:component-scan base-package="com.web"></context:component-scan>

    <context:property-placeholder location="file:D:/EasyProp/db.properties" ignore-unresolvable="false"/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
        <property name="prefix" value="/WEB-INF/jsp/" />  
        <property name="suffix" value=".jsp" />  
    </bean>

    <bean id="basicDataSource" 
         class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 

        <property name="driverClassName" value="${driver.classname}" />
        <property name="url" value="${driver.url}" />
        <property name="username" value="${username}" />
        <property name="password" value="${password}" />
<!--        <property name="initialSize" value="10"/> -->
<!--         <property name="maxActive"  value="25"/> -->
<!--         <property name="maxIdle" value="25"/>   -->
        <!-- <aop:scoped-proxy/> -->
    </bean> 
    <tx:annotation-driven />
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="mySessionFactory" />
    </bean>

    <!-- <bean id="dbUtil" class="com.web.utility.OnLoadStartUp" init-method="initialize">
        <property name="dataSource" ref="basicDataSource" />
    </bean> -->

    <!-- <bean id="loadOnStartUp" class="com.web.utility.LoadOnStartUp">
        <property name="baseService" ref="baseService"></property>
    </bean> -->

    <bean id="mySessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="basicDataSource" />
        <property name="annotatedClasses">
            <list>
                <value>com.web.bo.EmployeeBO</value>
                <value>com.web.bo.DepartmentBO</value>  
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hmb2ddl.auto">validate</prop>
                <prop key="hibernate.generate_statistics">true</prop>
                <prop key="hibernate.jdbc.fetch_size">10</prop>
                <prop key="hibernate.jdbc.batch_size">25</prop>
                <prop key="hibernate.jdbc.batch_versioned_data">true</prop>
                <prop key="hibernate.max_fetch_depth">3</prop>
                <prop key="hibernate.default_batch_fetch_size">8</prop>
                <prop key="hibernate.order_updates">true</prop>
                <prop key="hibernate.connection.release_mode">on_close</prop>
                <prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>
                <prop key="hibernate.bytecode.provider">javassist</prop>                
            </props>
        </property>
    </bean>
</beans>

当我试图从员工和部门表中获取所有数据但它只返回员工表中的数据时,我的命中 hql 查询代码如下:

List<EmployeeBO> empList = null; 
        empList = sessionFactory.getCurrentSession().createQuery("From "+employeeBO.getClass().getName()).list();   

上面的查询在数据库上如下所示。

select employeebo0_.EMPID as EMPID0_, employeebo0_.DEPTID as DEPTID0_, employeebo0_.EMPADDRESS as EMPADDRESS0_, employeebo0_.EMPAGE as EMPAGE0_, employeebo0_.EMPNAME as EMPNAME0_, employeebo0_.SALARY as SALARY0_ from EMPLOYEE employeebo0_

但我想使用 Eager fetching 获取员工表和部门表的所有数据。

【问题讨论】:

  • 所以,你不想要惰性抓取,而是渴望抓取,对吧?延迟获取正是在您需要之前不获取部门信息。

标签: java spring hibernate spring-mvc


【解决方案1】:

它按预期工作。 EmployeeBO 包含一个 DepartmentBO。 DepartmentBO 将在您访问时自动填写。

如果包含 EmployeeBO 的 Hibernate 会话已经结束,则不是这样。那么 EmployeeBO 是瞬态的,hibernate 不会获取丢失的对象。

要强制填写 DepartmentBO,您可以在 hql 代码中添加 fetch 子句。但这不再是偷懒了。

HQL

from EmployeeBO join fetch EmployeeBO.department 

应该做这项工作(将 EmployeeBO 替换为实际的实体名称)。

请参阅此处的休眠文档:https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html 以及此处的获取策略https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/performance.html#performance-fetching

从 cmets 中,您实际上想要对关系进行 Eager fetch,因此您需要将 fetchtype 声明为 Eager:

@ManyToOne(fetch=FetchType.EAGER)

应该修复它。在此处添加另一个文档:https://docs.oracle.com/javaee/6/api/javax/persistence/ManyToOne.html

【讨论】:

  • 是的,我知道 DepartmentBO 会自动填充,但是当我点击查询时它没有填充。你能解释一下关于会话的第二点吗?
  • 延迟获取就是这样:您只获取您明确要求的内容。任何相邻的结构都会在您需要时获取。你想要的(一个完全填充的结构,一个 SQL)被称为渴望获取。
  • Hibernate 使用包含实际数据的代理对象并管理缺失部分的加载。如果代理在休眠会话中,它只能访问任何丢失的部分。一旦会话结束,代理就只能访问对象中已经存在的部分。如果您将数据发送到另一个线程进行处理或自己管理会话,这一点很重要。有关休眠对象生命周期的信息,请参见此处docs.jboss.org/hibernate/orm/3.3/reference/en/html/…,如果您使用 Google 搜索,您会发现大量教程。
  • 我想用一个 sql 完全填充结构
  • 当我根据您的建议更改我的 hql 查询时它正在工作,但为什么在使用上述查询仅获取员工类详细信息时它没有填充所有结构。
【解决方案2】:

有两种方法可以做到这一点: 1) 使用 EAGER 获取类型 2) 获取员工后对每个员工调用 getDepartmentBO()

【讨论】:

    【解决方案3】:

    我认为您错过了延迟加载的注释。

    您必须在要延迟加载的关联上使用 (fetch=FetchType.LAZY)

    【讨论】:

    • LAZY 是集合的默认获取类型
    【解决方案4】:

    默认情况下休眠具有延迟加载。即它不会获取另一个表的数据。在你的情况下,如果你想要部门表的数据,如果你在休眠会话中,你将不得不调用 departmentBO 的 getter。注意:它将触发另一个查询。否则你也可以使用

    Hibernate.initialize(entity.getdepartmentBO())
    

    如果你想默认获取部门数据。使用以下代码

    @ManyToOne(fetch=FetchType.EAGER)
    

    【讨论】:

    • 哦,我想默认获取部门数据,我还添加了您提到的代码,但仍然无法正常工作。
    • 你能告诉我它现在正在触发什么查询吗?是否包括加入部门?
    • 我只添加了你提到的代码。我的查询如上所述。
    • 这不是真的,ManyToOne 默认加载了 EAGER。
    猜你喜欢
    • 1970-01-01
    • 2015-07-22
    • 1970-01-01
    • 1970-01-01
    • 2014-07-31
    • 2021-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多