抓取策略
Hibernate3 定义了如下几种抓取策略:
连接抓取(Join fetching)
Hibernate 通过在 SELECT 语句使用OUTER JOIN(外连接)来获得对象的关联实例或者关联集合。
code:
Query query = session.createQuery("from Student s left outer Classes c");
query.list();
是非延迟的抓取,不管你使用哪种抓取策略,定义为非延迟的类图,保证一定会被装载入内存。注意这可能意味着在一条 HQL 查询后紧跟着一系列的查询。
查询抓取(Select fetching)
另外再发送一条 SELECT 语句抓取当前对象的关联实体或集合。
集合:
<set name="studentSet" inverse="true" cascade="all" fetch="select">
类:
<many-to-one name="clazz" column="CID" cascade="save-update" class="Classes" not-null="true" fetch="select"/>
除非你显式的指定 lazy=”false” 禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条 select 语句。
子查询抓取(Subselect fetching)
另外再发送一条 SELECT 语句抓取在前面查询到(或者抓取到)的所有实体对象的关联集合。
Hibernate 会使用一个 subselect 重新运行原来的查询,一次性读入所有的实例。
<set name="studentSet" inverse="true" cascade="all" fetch="subselect">
除非你显式的指定 lazy=”false” 禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条 select 语句。
批量抓取(Batch fetching)
对查询抓取的优化方案,通过指定一个主键或外键列表,Hibernate 使用单条 SELECT 语句获取一批对象实例或集合。
批量抓取是延迟查询抓取的优化方案,你可以在两种批量抓取方案之间进行选择:在类级别和集合级别。
类级别
场景:
在一个session中加载了25个Student实例,每个实例都有一个引用成员clazz指向Classes。
如果你必须遍历整个 students 集合,对每个元素调用 getClazz() 方法,Hibernate 将会默认的执行 25 次 SELECT 查询,得到其clazz对象。
可通过在映射文件的 Classes 属性,显式声明 batch-size:
<class name="Classes" table="CLASSES" batch-size="25">
Hibernate 将只需要执行三次查询,分别为 10、10、 5。
集合级别
student集合有10个元素。
<set name="studentSet" inverse="true" cascade="all" batch-size="3">
如果整个的 batch-size 是 3,那么 Hibernate 将会分四次执行 SELECT 查询, 按照 3、3、3、1 的大小分别载入数据。
这里的每次载入的数据量还具体依赖于当前 Session 中未实例化集合的个数。
Hibernate会区分下列各种情况:
- Immediate fetching,立即抓取:当宿主被加载时,关联、集合或属性被立即抓取。
- Lazy collection fetching,延迟集合抓取:直到应用程序对集合进行了一次操作时,集合才被抓取(对集合而言这是默认行为)。
- Proxy fetching,代理抓取:对返回单值的关联而言,当其某个方法被调用,而非对其关键字进行 get 操作时才抓取。
默认情况下,Hibernate 3 对集合使用延迟查询抓取,对返回单值的关联使用延迟代理抓取。
若设置了 hibernate.default_batch_fetch_size,Hibernate 会对延迟加载采取批量抓取优化措施(这种优化也可能会在更细化的级别打开)。
懒(延迟)加载
类级别的懒加载
Classes classes = (Classes)session.load(Classes.class, 1L);//不会发出select语句
classes.getCname();//发出select语句
集合级别的懒加载
Classes c = (Classes)session.get(Classes.class, 1L);
Set<Student> students = c.getStudentSet();//没有发出select语句
System.out.println(students.size());//这时才发出select语句
for (Student s : students) {//这时也发出select语句
s.getSname();
}
通俗的讲,懒加载就是在需要一个对象的信息时才会发出select语句,从数据库或session缓存中取数据。
以上。。。