首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

【转载】Hibernate 原汁原味的四种抓取计策

2012-10-29 
【转载】Hibernate 原汁原味的四种抓取策略看到了一篇对hibernate抓取策略讲解比较详细且清晰的文章,转一下?

【转载】Hibernate 原汁原味的四种抓取策略

看到了一篇对hibernate抓取策略讲解比较详细且清晰的文章,转一下

?

原文:http://blog.csdn.net/Purking/archive/2009/12/30/5109151.aspx

?

最近在研究 Hibernate 的性能优化的时候碰到了"抓取策略", 由于以前没有详细的研究过,

?? ?所以到处找资料, 但是无论从一些讲 Hibernate 书籍,还是他人 Blog 中都没有找到详细

?? ?介绍 Hibernate 文档中所说的原汁原味的抓取策略, 综合懒加载等等特性混在了一起, 所

?? ?以在这自己在借鉴了他人的基础上研究了下原汁原味的 Hibernate 四种"抓取策略";

public class Customer { private long id; private String name; private Set<Order> orders; // getter/setter 略}?

?? ?Order :

?? ?public class Order { private long id; private String name; private Customer customer; // getter/setter略}?

Order 的映射文件是不变的, 放在这 :

<hibernate-mapping package="com.purking.strategys.endUpOne"> <class name="Order" table="Order_Table"> <id name="id"> <generator /> </id> <property name="name" length="20" column="Order_Name" /> <many-to-one name="customer" /> </class></hibernate-mapping>?

<hibernate-mapping package="com.purking.strategys.endUpOne"> <class name="Customer" table="Customer_Table" lazy="true"> <id name="id"> <generator /> </id> <property name="name" length="20" column="Cus_Name" /> <set name="orders" inverse="true" fetch="join" //---- Here <!-- 这里关闭懒加载是为了试验明显 --> lazy="false"> <key column="Cus_ID" /> <one-to-many /> </set> </class></hibernate-mapping>

?

我们使用如此查询语句 :

Customer c1 = (Customer)session.get(Customer.class, 11l);c1.getOrders().size();

?

Hibernate 发出的 SQL 语句为 :?

select customer0_.id as id0_1_, customer0_.Cus_Name as Cus2_0_1_, orders1_.Cus_ID as Cus3_3_, orders1_.id as id3_, orders1_.id as id1_0_, orders1_.Order_Name as Order2_1_0_, orders1_.Cus_ID as Cus3_1_0_ from Customer_Table customer0_ left outer join Order_Table orders1_ on customer0_.id=orders1_.Cus_ID where customer0_.id=?

?

在此, Hibernate 使用了 left outer join 连接两个表以一条 SQL 语句将 Order 集合

给初始化了;


?
<hibernate-mapping package="com.purking.strategys.endUpOne"> <class name="Customer" table="Customer_Table" lazy="true"> <id name="id"> <generator /> </id> <property name="name" length="20" column="Cus_Name" /> <set name="orders" inverse="true" fetch="select"> <key column="Cus_ID" /> <one-to-many /> </set> </class></hibernate-mapping>
?查询语句不变, 看看 Hibernate 发出的 SQL 语句:

Hibernate: select customer0_.id as id0_0_, customer0_.Cus_Name as Cus2_0_0_ from Customer_Table customer0_ where customer0_.id=?Hibernate: select orders0_.Cus_ID as Cus3_1_, orders0_.id as id1_, orders0_.id as id1_0_, orders0_.Order_Name as Order2_1_0_, orders0_.Cus_ID as Cus3_1_0_ from Order_Table orders0_ where orders0_.Cus_ID=??

这就是, 重新发出一条 SQL 语句, 初始化了 Orders 集合;

回来, 这样减少了与数据库的交互次数, 一次将每个对象的集合都给初始化了;

[他是如何这么智能的呢? 原来,他是将上一次查询的 SQL 语句作为这一次查询的 SQL

语句的 where 子查询, 所以上次查询到几个对象,那么这次就初始化几个对象的集

合----- 正因为如此, 所以 subselect 只在 <set> 集合中出现 ];

配置文件:?

<hibernate-mapping package="com.purking.strategys.endUpOne"> <class name="Customer" table="Customer_Table" lazy="true"> <id name="id"> <generator /> </id> <property name="name" length="20" column="Cus_Name" /> <set name="orders" inverse="true" fetch="subselect" lazy="true"> <key column="Cus_ID" /> <one-to-many /> </set> </class></hibernate-mapping>

?

测试的语句有变化 :

List results = session.createQuery("From Customer c where c.id in (11,14,17,20)").list();// 这里的四个 id 是我数据库中已经准备好的数据Customer c0 = (Customer)results.get(0);c0.getOrders().size();

?

这个时候再来看看 Hibernate 发出了什么样的 SQL 语句 :

Hibernate: select customer0_.id as id0_, customer0_.Cus_Name as Cus2_0_ from Customer_Table customer0_ where customer0_.id in ( 11 , 14 , 17 , 20 )Hibernate: select orders0_.Cus_ID as Cus3_1_, orders0_.id as id1_, orders0_.id as id1_0_, orders0_.Order_Name as Order2_1_0_, orders0_.Cus_ID as Cus3_1_0_ from Order_Table orders0_ where orders0_.Cus_ID in ( select customer0_.id from Customer_Table customer0_ where customer0_.id in ( 11 , 14 , 17 , 20 ) )

?

是不是发出的 SQL 语句形式与这个抓取策略的名字一样? Hibernate 的命名很清晰的;

一个 Customer 的 orders 集合的时候, Hibernate 还是发出了一条 SQL 语句,

不过这条 SQL 与是通过指定了 Order 表中的 Customer_ID 外键列表(2个), 这个

时候 Hibernate 会以一条 SQL 语句初始化 batch-size 指定的数量的 orders 集合;

[他是如何做到的呢? 通过一个主键或外键 列表 做到的, 他将 4 个 Customer 根据

batch-size 分成了两组, 一组有三个 Customer id 值的列表,第二组只有一个,

在初始化 orders 集合的时候就是根据这两个列表来初始化的]

配置文件 :

<hibernate-mapping package="com.purking.strategys.endUpOne"> <class name="Customer" table="Customer_Table" lazy="true"> <id name="id"> <generator /> </id> <property name="name" length="20" column="Cus_Name" /> <set name="orders" inverse="true" fetch="select" lazy="true" batch-size="3"> <key column="Cus_ID" /> <one-to-many /> </set> </class></hibernate-mapping>

?

在此,我关闭了集合默认的懒加载, 更有利于试验结果测试代码不变,

再来看看 Hibernate 发出的 SQL 语句 :

Hibernate: select customer0_.id as id0_, customer0_.Cus_Name as Cus2_0_ from Customer_Table customer0_ where customer0_.id in ( 11 , 14 , 17 , 20 )Hibernate: select orders0_.Cus_ID as Cus3_1_, orders0_.id as id1_, orders0_.id as id1_0_, orders0_.Order_Name as Order2_1_0_, orders0_.Cus_ID as Cus3_1_0_ from Order_Table orders0_ where orders0_.Cus_ID in ( ?, ?, ? )Hibernate: select orders0_.Cus_ID as Cus3_1_, orders0_.id as id1_, orders0_.id as id1_0_, orders0_.Order_Name as Order2_1_0_, orders0_.Cus_ID as Cus3_1_0_ from Order_Table orders0_ where orders0_.Cus_ID=?

原本需要四次 Select 的查询, 由于 Batch-size=3 只用了两次

就完成了;


总结:?

?? ?好了, 这里的四种抓取策略说明完了, 来全局看一下, 通过例子可以看出, 这四种抓取

策略并不是所有的情况都合适的, 例如, 如果我需要初始化的是一个单独的实体, 那

么 subselect 对其就没有效果,因为其本身就只需要查询一个对象, 所以 :?

    Join fetching , Select fetching 与 Batch-size 可以为单个实体的抓取进
    行性能优化;Join fetching , Select fetching ,Subselect fetching , Batch fetching
    都可以为集合的抓取进行性能优化;

注: 这里对于单个实体可以使用 Batch-size 可能会有点疑惑, 其实在 <class > 上是

具有 Batch-size 抓取策略的; 试想, 使用一个如果是一对一关系呢? 例如 Customer?

与 IdCard, 利用 HQL 查询出 4 个 Customer , 我们想一次性初始化 4 个 Customer?

的 IdCard 怎么办, 设置 <class name="IdCard" batch-size="4" > , 可能我们

想设置的地方是 <one-to-one batch-size> 但是这里没有提供这个属性, 可能是因为

如果设置了不好理解吧..