Hibernate学习之抓取策略与懒(延迟)加载

本文详细介绍了Hibernate中连接抓取、查询抓取、子查询抓取和批量抓取等四种抓取策略,以及它们如何影响数据加载效率。

抓取策略

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缓存中取数据。

以上。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值