我是如何学习Hibernate的(四)

前述

框架的出现是为了适应一些繁琐的重复的工作,从连接数据库到CRUD的实现,再到存储过程,事务。如果自己曾经从头到尾写过JDBC的实现,那么多半会怀疑人生。其实,在自己写JDBC的时候,可能很多人都违背DRY(Don’t Repeat Youself)的原则。框架出现的意义就是前辈们将自己踩过的坑填平,让后辈能够走得更平坦一些。

抓取策略

  • 立即检索:立即查询,在执行查询语句时,立即查询所有数据。
  • 延迟检索:延迟查询,在执行查询语句以后,在需要数据时再查询(懒加载)。
  • 类级别检索:当前类的属性获取是否需要延迟。
    get:立即检索
    Load:延迟检索,默认情况,如果只使用OID的值不进行查询,如果要使用其他属性值,将进行查询。
    Customer.hbm.xml
    lazy默认为true,如果设置为false则会立即检索(不使用代理)。
  • 关联级别检索:当前类关联的别一个类是否需要延迟。

    一对多、多对多

    容器提供了两个属性:fetch、lazy
    以Customer和Order作为例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package com.hibernate3;
    //Customer类及配置文件
    public class Customer {

    private Integer uid;
    private String name;
    private Set<Order> orderSet = new HashSet<Order>();
    }

    <hibernate-mapping>
    <class name="com.hibernate3.Customer" table="customer">
    <id name="uid" column="id" >
    <generator class="native" />
    </id>
    <set name="orderSet" fetch="select" lazy="false">
    <key column="customer_id" />
    <one-to-many class="com.hibernate3.Order"/>
    </set>
    <property name="name" column="name" />
    </class>
    </hibernate-mapping>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Order类及其配置文件
package com.hibernate3;

public class Order {

private Integer oid;
private Integer price;
private Customer customer;

<hibernate-mapping>
<class name="com.hibernate3.Order" table="t_order">
<id name="oid" column="id" >
<generator class="native" />
</id>
<many-to-one name="customer" class="com.hibernate3.Customer" column="customer_id">
</many-to-one>
<property name="price" />
</class>
</hibernate-mapping>

}
1
2
3
4
5
6
7
8
9
10
11
12
13
//业务逻辑
//1 查询订单
Customer customer = (Customer) session.get(Customer.class, 1);
System.out.println(customer.getCname());

//2 查询客户订单数
Set<Order> orderSet = customer.getOrderSet();
System.out.println(orderSet.size());

//3 查询客户订单详情
for (Order order : orderSet) {
System.out.println(order);
}
  • fetch:确定使用SQL格式(Join fetching、Select fetching、Subselect fetching)
    Join:使用Outer join(外连接)来获取关联实例或者关联集合。当fetch=join时,lazy无效。
    Select:如果没有指定lazy=false,禁止延迟加载,那么当真正访问关联关系时,会执行另一条SQL。
    Subselect:另外发送一条SQL,抓去前面抓取到的所有实体对象的集合。当真正访问关联关系时,会执行另一条SQL。必须使用query,否则看不到效果

  • lazy:关联对象是否延迟(Immediate、Lazy collection、Extra-lazy)
    Immeaiate 立即抓取 (lazy=flase):当宿主被加载时,关联、集合属性被立即抓取。
    Lazy collection fetching 延迟加载集合 (lazy=true):直到应用程序对集合进行了一次操作时,集合才被抓取(默认)。
    Extra-lazy 集合抓取 (lazy=extra):对集合中的每个元素而言,都是直到需要时才进行访问数据库。(适用于非常大的集合)

  • fetch=”join”,lazy无效,底层会使用迫切左外连接,只是用一条select语句将所有的内容全部查询。

  • fetch=”select” lazy=”false” ,立即查询,先查询客户select,再查询订单select。(同时执行两条语句)
  • fetch=”select” lazy=”true” ,立即查询第一条语句,当需要Order数据时,再查询第二条。
  • fetch=”select” lazy=”extra” ,立即查询第一条语句,当需要时,第二条语句使用聚合函数select count(*)查询,一共三条语句。

fetch=”subselect” lazy=”和上面一样” ,将使用子查询。必须使用Query,不然看不到效果。
业务逻辑变为:

//1 查询客户
List<Customer> allCustomer = session.createQuery("from Customer").list();
Customer customer = allCustomer.get(0);
System.out.println(customer.getCname());

//2 查询客户订单数
Set<Order> orderSet = customer.getOrderSet();
System.out.println(orderSet.size());

//3 查询客户订单详情
for (Order order : orderSet) {
    System.out.println(order);
}
  • fetch=”subselect” lazy=”false” ,同时执行两条select,第二条使用子查询(select …from…where id in(select…))
  • fetch=”subselect” lazy=”true” ,第二条语句延迟查询。
  • fetch=”subselect” lazy=”extra” ,第二条语句使用聚合函数,第三条语句使用子查询。