我知道上面的问题很常见,但我只是想知道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)
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;
}
}
<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>
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;
}
}
<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>
以下是获取员工列表的代码块:
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);
}
现在,这里的移动号是Employee的子记录,它根据Employee.hbm.xml中的hibernate配置懒惰地加载了Hibernate(lazy = true)
在上面的代码中,打印员工姓名后,我打印的是手机号码 员工通过迭代Set手机。
我已经检查过并发现mobileSet的迭代实际上正在获取mobileNumbers。 即。
for(Mobile mobile : mobileSet) {
System.out.println(mobile.getMobileNumber());
}
那么,它是如何发生的?因为我没有使用任何特定于hibernate的API来获取延迟加载的子记录。只是迭代一组手机号码。
然后Hibernate如何在内部获取子记录?在迭代mobileSet时Hibernate正在做什么后台工作?
请帮助理解我的疑问。
答案 0 :(得分:2)
在hibernate中,只要访问延迟加载的属性并且它仍由em管理,就会触发延迟加载。如果在实体与实体管理器分离时访问延迟加载的属性,则会得到org.hibernate.LazyInitializationException
要将逻辑应用于您的示例: mobile.getMobileNumber()将触发代码中的延迟加载。然后,Hibernate将自动向数据库发出查询。这是因为hibernate为延迟加载的属性实例化代理对象,一旦你尝试访问这些代理,hibernate会尝试从数据库加载它们。如果对象被管理,这将起作用,如果实体被分离,这将导致前面提到的异常。根本不需要使用hibernate API来触发延迟加载,它只是在访问惰性配置属性时自动发生
答案 1 :(得分:1)
在您的Employee.hbm.xml文件中,您已声明Mobile的抓取策略是惰性的。 这告诉hibernate为与Employee对应的表生成一个简单的SQL语句,而不与相应的Mobile表进行任何连接。 但是当调用employee.getMobiles()时 Hibernate将使用带有前表的主键的where子句向后一个表发出select查询。
这里实现提取的方式会导致臭名昭着的N+1 problem
答案 2 :(得分:0)
本主题可以帮助您了解延迟加载背后的技巧: