Hibernate检索行为
以下讲解都是基于hibernate-distribution-3.6.0.Beta2版本
了解Hibernate的检索行为,有助于优化Hibernate的查询性能。
持久类配置文件的类级别和关联级别的默认检索策略是延迟检索(hibernate2.x默认是立即检索),即<class lazy="true">和<set lazy="true">
Customer.hbm.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.Customer" table="CUSTOMERS">
<id name="id" column="ID" type="long">
<generator column="NAME" type="string"/>
<set name="orders" cascade="all" inverse="true">
<key column="CUSTOMER_ID"/>
<one-to-many + orderNum);
Query query = session.createFilter(customer.getOrders(), "where this.price > 100"); //不论对象是否已经在Session缓存中,都会重新到数据库中查询符合条件的订单
List orders = query.list();
System.out.println("过滤后的订单数量:" + orders.size());
/**Output:
Hibernate: select customer0_.ID as ID1_0_, customer0_.NAME as NAME1_0_ from CUSTOMERS customer0_ where customer0_.ID=?
executing customer.getOrders().size()
Hibernate: select orders0_.CUSTOMER_ID as CUSTOMER3_1_1_, orders0_.ID as ID1_, orders0_.ID as ID2_0_, orders0_.ORDER_NO as ORDER2_2_0_, orders0_.CUSTOMER_ID as CUSTOMER3_2_0_, orders0_.PRICE as PRICE2_0_ from ORDERS orders0_ where orders0_.CUSTOMER_ID=?
订单数量:3
Hibernate: select order0_.ID as ID2_, order0_.ORDER_NO as ORDER2_2_, order0_.CUSTOMER_ID as CUSTOMER3_2_, order0_.PRICE as PRICE2_ from ORDERS order0_ where order0_.CUSTOMER_ID = ? and order0_.PRICE>100
过滤后的订单数量:2
*/
如果配置文件中的关联级别设置为迫切左外连接检索,HQL会忽略它,执行立即检索。QBC会遵循配置文件的迫切左外连接检索策略
使用HQL显示执行迫切左外连接检索
迫切左外连接:left join fetch
迫切左外连接特点:
1.Query和Criteria的list()方法返回的集合中存放客户对象引用,关联的所有订单对象也都初始化了
2.没有订单的客户也会检索出来
Query query = session.createQuery("from Customer c left join fetch c.orders o where c.id = ?");
query.setLong(0, 26);
Iterator customers = query.list().iterator();
while (customers.hasNext()) {
Customer customer = (Customer)customers.next();
System.out.println("Customer Id:" + customer.getId());
System.out.println("executing customer.getOrders().iterator()");
for (Iterator orders = customer.getOrders().iterator(); orders.hasNext();) { //执行customer.getOrders().iterator()时没有select语句,因为所有订单都关联并初始化了
Order order = (Order)orders.next();
System.out.println(order.getOrderNo());
}
}
/**Output:
Hibernate: select customer0_.ID as ID1_0_, orders1_.ID as ID2_1_, customer0_.NAME as NAME1_0_, orders1_.ORDER_NO as ORDER2_2_1_, orders1_.CUSTOMER_ID as CUSTOMER3_2_1_, orders1_.PRICE as PRICE2_1_, orders1_.CUSTOMER_ID as CUSTOMER3_1_0__, orders1_.ID as ID0__ from CUSTOMERS customer0_ left outer join ORDERS orders1_ on customer0_.ID=orders1_.CUSTOMER_ID where customer0_.ID=?
Customer Id:26
executing customer.getOrders().iterator()
no_002
no_001
no_003
Customer Id:26
executing customer.getOrders().iterator()
no_002
no_001
no_003
Customer Id:26
executing customer.getOrders().iterator()
no_002
no_001
no_003
*/
以上代码会重复引用Customer对象3次,用Set去除重复,如:Iterator customers = new HashSet(query.list()).iterator();再次执行如下输出。
/**Output:
Hibernate: select customer0_.ID as ID1_0_, orders1_.ID as ID2_1_, customer0_.NAME as NAME1_0_, orders1_.ORDER_NO as ORDER2_2_1_, orders1_.CUSTOMER_ID as CUSTOMER3_2_1_, orders1_.PRICE as PRICE2_1_, orders1_.CUSTOMER_ID as CUSTOMER3_1_0__, orders1_.ID as ID0__ from CUSTOMERS customer0_ left outer join ORDERS orders1_ on customer0_.ID=orders1_.CUSTOMER_ID where customer0_.ID=?
Customer Id:26
executing customer.getOrders().iterator()
no_001
no_003
no_002
*/
左外连接:left join
左外连接特点:
1.Query的list()方法返回的集合中存放客户对象引用,但关联的订单对象并没有初始化
2.没有订单的客户也会检索出来
Query query = session.createQuery("select c from Customer c left join c.orders o where c.id = 26");
for (Iterator customers = new HashSet(query.list()).iterator(); customers.hasNext();) { //用Set去重
Customer customer = (Customer)customers.next();
System.out.println("Customer Id:" + customer.getId());
System.out.println("executing customer.getOrders().iterator()");
for (Iterator orders = customer.getOrders().iterator(); orders.hasNext();) { //执行customer.getOrders().iterator()时执初始化订单
Order order = (Order)orders.next();
System.out.println(order.getOrderNo());
}
}
/**Output:
Hibernate: select customer0_.ID as ID1_, customer0_.NAME as NAME1_ from CUSTOMERS customer0_ left outer join ORDERS orders1_ on customer0_.ID=orders1_.CUSTOMER_ID where customer0_.ID=26
Customer Id:26
executing customer.getOrders().iterator()
Hibernate: select orders0_.CUSTOMER_ID as CUSTOMER3_1_1_, orders0_.ID as ID1_, orders0_.ID as ID2_0_, orders0_.ORDER_NO as ORDER2_2_0_, orders0_.CUSTOMER_ID as CUSTOMER3_2_0_, orders0_.PRICE as PRICE2_0_ from ORDERS orders0_ where orders0_.CUSTOMER_ID=?
no_001
no_002
no_003
*/
内连接:inner join / join
内连接特点:
1.Query的list()方法返回的集合中存放Object[]的引用,每个Object[]包含两个对象,一个是Customer,一个是Order。而Customer关联的订单对象并没有初始化
2.没有订单的客户不会检索出来
Query query = session.createQuery("from Customer c inner join c.orders o where c.id = :id");
query.setLong("id", 26);
for (Iterator pairs = query.list().iterator(); pairs.hasNext();) {
Object[] pair = (Object[])pairs.next();
Customer customer = (Customer)pair[0];
Order unRefOrder = (Order)pair[1];
System.out.println("Customer Id:" + customer.getId());
System.out.println("executing customer.getOrders().iterator()");
for (Iterator orders = customer.getOrders().iterator(); orders.hasNext();) { //执行customer.getOrders().iterator()时执初始化订单,执行select语句,但查出来的订单已经在Session缓存中了,所以不会再创建Order对象,直接和Session缓存中没有关联的订单关联
Order order = (Order)orders.next();
System.out.println(order.getOrderNo());
}
}
/**Output:
Hibernate: select customer0_.ID as ID1_0_, orders1_.ID as ID2_1_, customer0_.NAME as NAME1_0_, orders1_.ORDER_NO as ORDER2_2_1_, orders1_.CUSTOMER_ID as CUSTOMER3_2_1_, orders1_.PRICE as PRICE2_1_ from CUSTOMERS customer0_ inner join ORDERS orders1_ on customer0_.ID=orders1_.CUSTOMER_ID where customer0_.ID=?
Customer Id:26
executing customer.getOrders().iterator()
Hibernate: select orders0_.CUSTOMER_ID as CUSTOMER3_1_1_, orders0_.ID as ID1_, orders0_.ID as ID2_0_, orders0_.ORDER_NO as ORDER2_2_0_, orders0_.CUSTOMER_ID as CUSTOMER3_2_0_, orders0_.PRICE as PRICE2_0_ from ORDERS orders0_ where orders0_.CUSTOMER_ID=?
no_003
no_002
no_001
Customer Id:26
executing customer.getOrders().iterator()
no_003
no_002
no_001
Customer Id:26
executing customer.getOrders().iterator()
no_003
no_002
no_001
*/
以上代码存在重复Customer对象,用Set去除重复
Query query = session.createQuery("from Customer c inner join c.orders o where c.id = :id");
query.setLong("id", 26);
Set<Customer> customers = new HashSet<Customer>(); //去除重复
for (Iterator pairs = query.list().iterator(); pairs.hasNext();) {
Object[] pair = (Object[])pairs.next();
Customer customer = (Customer)pair[0];
Order unRefOrder = (Order)pair[1];
customers.add(customer);
}
for (Iterator it = customers.iterator(); it.hasNext();) {
Customer customer = (Customer)it.next();
System.out.println("Customer Id:" + customer.getId());
System.out.println("executing customer.getOrders().iterator()");
for (Iterator orders = customer.getOrders().iterator(); orders.hasNext();) {
Order order = (Order)orders.next();
System.out.println(order.getOrderNo());
}
}
/**Output:
Hibernate: select customer0_.ID as ID1_0_, orders1_.ID as ID2_1_, customer0_.NAME as NAME1_0_, orders1_.ORDER_NO as ORDER2_2_1_, orders1_.CUSTOMER_ID as CUSTOMER3_2_1_, orders1_.PRICE as PRICE2_1_ from CUSTOMERS customer0_ inner join ORDERS orders1_ on customer0_.ID=orders1_.CUSTOMER_ID where customer0_.ID=?
Customer Id:26
executing customer.getOrders().iterator()
Hibernate: select orders0_.CUSTOMER_ID as CUSTOMER3_1_1_, orders0_.ID as ID1_, orders0_.ID as ID2_0_, orders0_.ORDER_NO as ORDER2_2_0_, orders0_.CUSTOMER_ID as CUSTOMER3_2_0_, orders0_.PRICE as PRICE2_0_ from ORDERS orders0_ where orders0_.CUSTOMER_ID=?
no_002
no_003
no_001
*/
迫切内连接:inner join fetch / join fetch
迫切内连接特点:
1.Query的list()方法返回的集合中存放客户对象引用,关联的所有订单对象也都初始化了
2.没有订单的客户不会检索出来(和迫切左连接唯一的差别)
Query query = session.createQuery("from Customer c inner join fetch c.orders o where c.id = :id");
query.setLong("id", 26);
for (Iterator customers = new HashSet(query.list()).iterator(); customers.hasNext();) { //用Set去重
Customer customer = (Customer)customers.next();
System.out.println("Customer Id:" + customer.getId());
System.out.println("executing customer.getOrders().iterator()");
for (Iterator orders = customer.getOrders().iterator(); orders.hasNext();) { //执行customer.getOrders().iterator()时没有select语句,因为所有订单都关联并初始化了
Order order = (Order)orders.next();
System.out.println(order.getOrderNo());
}
}
/**Output:
Hibernate: select customer0_.ID as ID1_0_, orders1_.ID as ID2_1_, customer0_.NAME as NAME1_0_, orders1_.ORDER_NO as ORDER2_2_1_, orders1_.CUSTOMER_ID as CUSTOMER3_2_1_, orders1_.PRICE as PRICE2_1_, orders1_.CUSTOMER_ID as CUSTOMER3_1_0__, orders1_.ID as ID0__ from CUSTOMERS customer0_ inner join ORDERS orders1_ on customer0_.ID=orders1_.CUSTOMER_ID where customer0_.ID=?
Customer Id:26
executing customer.getOrders().iterator()
no_003
no_002
no_001
*/