NO TRY , NO HIGH
@OneToMany(fetch = FetchType.LAZY, mappedBy = "employee",cascade=CascadeType.ALL)
public Set<Schedule> getSchedules() {
return schedules;
}
DAO层代码中@OneToOne,@ManyToOne,@OneToMany,@ManyToMany只是定义了entity之间的关系,还需要通过fetch属性指定加载方式。Hibernate定义了两种加载方式:
如果是EAGER,那么表示取出这条数据时,它关联的数据也同时取出放入内存中
如果是LAZY,那么取出这条数据时,它关联的数据并不取出来,在同一个session中,什么时候要用,就什么时候取(再次访问数据库)。
在Hibernate 二个或者多个对象有关联的情况,并且设置fetch = FetchType.EAGER。在执行hql查询语句的时候,查询一个表,将会随便查询出所有相关联的表,
即:发出一条sql语句后,继续发出N条sql语句。
这种问题在多对一关联(最为常见)尤为严重。假如存在course和schedule表,且为OneToMany。course表存在10条数据,schedule表存在100条数据。
当我们需要查出所有的course时,查询会产生
1(select * from course)+10(select schedule … where courseId=XXX)条sql语句。
下面是摘自martin fowler对于lazy loading的解释,原文链接为Â
There are four main varieties of lazy load.
- Lazy Initialization uses a special marker value (usually null) to indicate a field isn’t loaded. Every access to the field checks the field for the marker value and if unloaded, loads it.
- Virtual Proxy is an object with the same interface as the real object. The first time one of its methods are called it loads the real object and then delegates.
- Value Holder is an object with a getValue method. Clients call getValue to get the real object, the first call triggers the load.
- A ghost is the real object without any data. The first time you call a method the ghost loads the full data into its fields.
在前后端分离的项目中,如果设置FetchType.EAGER。需要做如下配置
将@ResponseBody注解加入到controller的方法中,如下:
@RequestMapping(value = "/employees", method = RequestMethod.GET)
public @ResponseBody List<Employee> getEmployees() {
return employeeService.getEmployees();
}
当在一个遗留项目,我们之前用到了jsp,现在要前后端分离使用angular,在这种情况下,就必须使用到lazy loading。
那么hibernate 本身在向前端传数据时就会出现如下问题:
Error 500 Attempted to serialize java.lang.Class: org.hibernate.proxy.HibernateProxy. Forgot to register a type adapter?
原因就是无法对设置了lazy loading 的外键部分进行加载。
解决方法是需要工具对其进行序列化,链接here
完成上述配置后需要在dao层显示的破坏掉lazy loading
for (Customer customer : customerList) {
// if (customer.getEmployee() != null) {
// customer.getEmployee().getEmail();
// }
Hibernate.initialize(customer.getEmployee());
}
最后想说的是,Lazy Loading 这个问题并不是Hibernate 独有,事实上很多Object/Relational Mapping (ORM) 的程式库,为了要争取一些执行上的效率、降低内存空间与数据传输负荷,几乎都采用类似的作法。