Hibernate检索行为

[color=red]以下讲解都是基于hibernate-distribution-3.6.0.Beta2版本[/color]

[b]了解Hibernate的检索行为,有助于优化Hibernate的查询性能。[/b]

持久类配置文件的类级别和关联级别的默认检索策略是延迟检索(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 class="native"/>
</id>

<property name="name" column="NAME" type="string"/>
<set name="orders" cascade="all" inverse="true">
<key column="CUSTOMER_ID"/>
<one-to-many class="com.Order"/>
</set>
</class>
</hibernate-mapping>

Hibernate用的最多的两种检索方式是HQL和QBC。
HQL检索方式:
优点:更接近SQL,代码简洁、灵活、可读性好。功能最强大。
缺点:需要写字符HQL语句。
Query query = session.createQuery("from Customer c where c.name = :name order by c.id desc");
query.setString(":name", "Phil");
List result = query.list();
QBC检索方式:
优点:更面向对象查询。动态查询方便。
缺点:功能和可读性不如HQL。
Criteria criteria = session.createCriteria(Customer.class);
Criterion criterion = org.hibernate.criterion.Expression.eq("name", "Phil");
Order order = org.hibernate.criterion.Order.desc("id");
criteria.add(criterion);
criteria.addOrder(order);
List result = criteria.list();

对于类级别,Session的get()是立即检索,不会考虑配置文件是否采用延迟检索。Session的load()方法会遵循配置文件的检索策略,如果是延迟检索,则会创建一个代理类实例,此代理类实例只有OID属性被赋值,而不会立即查数据库。
对于关联级别,Session的get()和load()方法都会遵循配置文件的检索策略。
注意:此版本已没有find()方法。
Customer customer = (Customer)session.load(Customer.class, new Long(26));
if (customer != null) {
System.out.println("executing customer.getId()"); //不会执行select语句,返回load的第二个参数值
System.out.println(customer.getId());
System.out.println("executing customer.getName()");
System.out.println(customer.getName()); //执行select语句
}
/**Output:
executing customer.getId()
26
executing customer.getName()
Hibernate: select customer0_.ID as ID1_0_, customer0_.NAME as NAME1_0_ from CUSTOMERS customer0_ where customer0_.ID=?
Phil
*/

如果某个持久化实例已经在Session缓存中,则不会到数据库中查询,直接返回Session缓存中的持久化实例
System.out.println("executing first get()");
Customer customer1 = (Customer)session.get(Customer.class, new Long(26));
System.out.println("executing second get()");
Customer customer2 = (Customer)session.get(Customer.class, new Long(26));
System.out.println("executing third get()");
Customer customer3 = (Customer)session.get(Customer.class, new Long(26));
/**Output:
executing first get()
Hibernate: select customer0_.ID as ID1_0_, customer0_.NAME as NAME1_0_ from CUSTOMERS customer0_ where customer0_.ID=?
executing second get()
executing third get()
*/

由于关联对象是延迟检索,所以直到使用关联对象时才会到数据库查询。使用不知道关联对象的OID,因为创建关联对象的代理,而仅仅是创建Set对象的代理。
Customer customer = (Customer)session.get(Customer.class, new Long(26));
System.out.println("executing getOrders()");
Set orders = customer.getOrders(); //仅仅返回Set代理
System.out.println("executing iterator()");
orders.iterator(); //执行select语句
/**Output:
Hibernate: select customer0_.ID as ID1_0_, customer0_.NAME as NAME1_0_ from CUSTOMERS customer0_ where customer0_.ID=?
executing getOrders()
executing 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_ from ORDERS orders0_ where orders0_.CUSTOMER_ID=?
*/

如果一个客户有很多订单,而我只想查看其中某部份订单,如果不做过滤就会导致不需要的订单对象也被查询到Session缓存,这很让费资源,也影响性能。这时可以过滤感兴趣的订单。
Customer customer = (Customer)session.get(Customer.class, new Long(26));
System.out.println("executing customer.getOrders().size()");
int orderNum = customer.getOrders().size(); //这里会执行select语句查询用户所有订单。
System.out.println("订单数量:" + 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
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值