Hibernate 中子记录的延迟加载如何工作?

San*_*ndy 5 java hibernate

我知道上面的问题很常见,但我只是想确切地知道 Hibernate 何时以及如何获取延迟加载的子记录。

下面是示例表结构:

表结构:

employee_table(e_id, e_name, e_sal)
(100, XYZ, 20000)

mobile_table(m_id, m_number, e_id)
(1, 8728271817, 100)
(2, 0983813919, 100)
Run Code Online (Sandbox Code Playgroud)

员工.java

public class Employee implements Serializable {

    private static final long serialVersionUID = 1930751473454928876L;

    private long employeeId;
    private String employeeName;
    private double employeeSal;

    private Set<Mobile> mobiles;

    public long getEmployeeId() {
        return employeeId;
    }
    public void setEmployeeId(long employeeId) {
        this.employeeId = employeeId;
    }
    public String getEmployeeName() {
        return employeeName;
    }
    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }
    public double getEmployeeSal() {
        return employeeSal;
    }
    public void setEmployeeSal(double employeeSal) {
        this.employeeSal = employeeSal;
    }
    public Set<Mobile> getMobiles() {
        return mobiles;
    }
    public void setMobiles(Set<Mobile> mobiles) {
        this.mobiles = mobiles;
    }
}
Run Code Online (Sandbox Code Playgroud)

员工.hbm.xml

<hibernate-mapping>
    <class name="edu.sandip.hibernate.Employee" table="EMPLOYEE_T">
        <id name="employeeId" column="e_id" type="long">
            <generator class="increment" />
        </id>
        <property name="employeeName" column="e_name" type="string" />
        <property name="employeeSal" column="e_sal" type="double" />

        <set name="mobiles" table="MOBILE_T" inverse="true" lazy="true" fetch="select" >
            <key>
                <column name="e_id" not-null="true" />
            </key>
            <one-to-many class="edu.sandip.hibernate.Mobile" />
        </set>
    </class>
</hibernate-mapping>
Run Code Online (Sandbox Code Playgroud)

移动.java

public class Mobile implements Serializable {

    private static final long serialVersionUID = 6279006639448045512L;

    private long mobId;
    private String mobileNumber;

    private Employee employee;

    public long getMobId() {
        return mobId;
    }
    public void setMobId(long mobId) {
        this.mobId = mobId;
    }
    public String getMobileNumber() {
        return mobileNumber;
    }
    public void setMobileNumber(String mobileNumber) {
        this.mobileNumber = mobileNumber;
    }
    public Employee getEmployee() {
        return employee;
    }
    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((mobileNumber == null) ? 0 : mobileNumber.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Mobile other = (Mobile) obj;
        if (mobileNumber == null) {
            if (other.mobileNumber != null)
                return false;
        } else if (!mobileNumber.equals(other.mobileNumber))
            return false;
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

移动.hbm.xml

<hibernate-mapping>
    <class name="edu.sandip.hibernate.Mobile" table="MOBILE_T">
        <id name="mobId" column="m_id" type="long">
            <generator class="increment" />
        </id>
        <property name="mobileNumber" column="m_number" type="string" />
        <many-to-one name="employee" class="edu.sandip.hibernate.Employee" fetch="select">
            <column name="e_id" not-null="true" />
        </many-to-one>
    </class>
</hibernate-mapping>
Run Code Online (Sandbox Code Playgroud)

以下是获取员工列表的代码块:

public List<Employee> getAllEmployees() {
    List<Employee> list = null;
    Session session = null;
    try {
        session = getSession();
        Query query = session.createQuery("FROM Employee");
        list = query.list();
        for(Employee employee : list) {
            System.out.println("Emaployee Name: " + employee.getEmployeeName);
            Set<Mobile> mobileSet = employee.getMobiles();
            System.out.println("Mobile Numbers: ");
            for(Mobile mobile : mobileSet) {
                System.out.println(mobile.getMobileNumber());
            }
        }
    } catch(Exception e) {
        e.printStackTrace();
    } finally {
        if(session != null) {
            System.out.println("session is still alive");
            releaseSession(session);
        }
    }
    return (list);
}
Run Code Online (Sandbox Code Playgroud)

现在,这里的手机号码是 Employee 的子记录,它由 Hibernate 根据 Employee.hbm.xml 中的 hibernate 配置延迟加载(lazy = true)

在上面的代码中,打印员工姓名后,我通过迭代 Set mobiles 来打印该员工的手机号码。

我检查了一下,发现mobileSet的迭代实际上是在获取mobileNumbers。IE

for(Mobile mobile : mobileSet) {
    System.out.println(mobile.getMobileNumber());
}
Run Code Online (Sandbox Code Playgroud)

那么,这是怎么发生的?因为我没有使用任何 hibernate 特定的 API 来获取延迟加载的子记录。只是迭代手机号码集。

那么Hibernate内部是如何获取子记录的呢?当我迭代 mobileSet 时,Hibernate 正在执行什么后台工作?

请帮助理解我的疑问。

Max*_* B. 0

本主题可以帮助您了解延迟加载背后的技巧:

代理如何在 Hibernate/JPA 中加载惰性属性