`

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 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
*/
0
0
分享到:
评论

相关推荐

    hibernate的延迟检索在轻量级J2EE框架中的应用

    - **Spring集成**:Spring可以很好地集成Hibernate,通过Spring的事务管理器,可以更好地控制事务边界,同时利用Spring的AOP特性,可以更加灵活地管理延迟加载的行为。 - **业务逻辑优化**:在业务逻辑层,合理使用...

    hibernate-jar

    4. **Criteria API**和**HQL(Hibernate Query Language)**:这两者都是查询语言,用于从数据库检索数据。Criteria API提供了一种类型安全的方式来构建查询,而HQL更接近于SQL,但与特定的ORM模型相关联。 5. **...

    hibernate视频

    综上所述,“邹波hibernate50讲”视频教程覆盖了Hibernate框架的基础知识、实体类设计、对象-关系映射、查询检索、性能优化以及一些高级特性等内容。对于初学者来说,这是一个全面了解并掌握Hibernate技术的好资源。

    Hibernate电子书(全)

    正确设置`inverse`可以确保Hibernate在处理关联关系时的行为符合预期。 #### 一对一与多对多实体映射 Hibernate支持一对一和多对多关系的映射,分别通过`@OneToOne`和`@ManyToMany`注解实现。这些映射策略使得复杂...

    优化Hibernate性能的几点建议

    为了确保Hibernate的最佳性能,还需要定期监控Hibernate的行为并根据需要调整配置。例如,将`hibernate.show_sql`设置为`true`可以帮助调试SQL语句的执行情况,从而发现潜在的问题。此外,还可以通过分析Hibernate的...

    Hibernate3.2整套源码

    3. **Hibernate检索策略**:包括“立即加载”和“延迟加载”,可以根据需求选择何时加载关联的对象。 4. **类型系统增强**:增加了对枚举类型的支持,以及更加灵活的类型转换机制。 5. **JPA支持**:Hibernate 3.2...

    hibernate(api_介绍)

    - **Interceptor**:此接口允许开发者监听Hibernate内部发生的事件,如对象加载、删除、保存和更新,从而实现定制的行为,如记录数据更改日志。 4. **映射接口** - **Type**接口:定义了Hibernate的映射类型,将...

    Hibernate5.0用户手册中文版本

    Hibernate 是一个基于 Java 的关系型持久层框架,它提供了一个高效、灵活的解决方案来存储和检索数据。本手册是 Hibernate 5.0 的中文版本,旨在帮助开发者快速掌握 Hibernate 的使用和配置。 Architecture(体系...

    hibernate源码

    6. **Query和Criteria API**:Hibernate提供HQL(Hibernate Query Language)和Criteria API两种查询方式,它们都是面向对象的查询语言,方便开发者以更符合Java思维的方式进行数据检索。 7. **事务处理**:...

    hibernate5官方文档,HTML+PDF

    9. **懒加载(Lazy Loading)**:这是一种性能优化策略,延迟加载关联对象,直到真正需要它们时才从数据库获取,避免了不必要的数据检索。 10. **缓存策略**:Hibernate提供了第一级缓存(Session级别的)和第二级...

    hibernate-3.2.6

    开发者可以通过修改此文件来调整Hibernate的行为。 3. **实体类和映射文件(.hbm.xml)**:每个数据库表对应一个Java实体类,通过XML映射文件定义类与表之间的关系。字段映射、主键生成策略、关联关系(一对一、一...

    hibernate中五个核心接口

    它允许开发者设置各种属性来定制 Hibernate 的行为。 **特点:** - **加载配置文件**:Configuration 主要用于加载配置文件,如 `hibernate.cfg.xml` 或其他 XML 配置文件。 - **设置属性**:可以设置 Hibernate ...

    hibernate-search-5.3.0.Final-dist

    例如,包含的JAR文件提供了Hibernate Search的核心功能,而相关的XML配置文件可以帮助开发者定制搜索引擎的行为。 总结来说,Hibernate Search 5.3.0.Final是SSH开发环境下提升搜索功能的理想选择。其强大的全文...

    Hibernate5用户手册中文版

    4. 持久化Context(上下文)章节,解释了实体的持久化机制,包括实体的创建、删除、检索以及状态的刷新等操作。此外,还介绍了如何管理和使用游离态数据。 5. 访问数据库部分,讲解了Hibernate如何通过不同的连接...

    hibernate-search-4.3.0.zip

    Hibernate Search是Java领域中一个强大的全文搜索引擎,它将Apache Lucene的功能与Hibernate ORM框架相结合,为Java应用程序提供了便捷的、高性能的全文检索功能。在本文中,我们将深入探讨Hibernate Search 4.3.0...

    hibernate项目

    这个文件是项目启动时读取的,用于配置Hibernate的行为。 2. **实体类(Entity)**:在Hibernate中,实体类代表数据库中的表,通过注解(如`@Entity`,`@Table`)来标记。实体类的属性与表的列对应,使用`@Column`...

    hibernate annotations 中文参考手册

    可以通过 `hibernate.hbm2ddl.auto` 配置属性控制自动生成行为。 ##### 外部配置 除了通过注解配置实体映射之外,还可以使用 XML 文件或者基于 Java 的配置方式来定制更复杂的映射规则。 #### 总结 通过使用 ...

    Hibernate开发指南

    - 设置Hibernate的行为参数:如自动创建表、日志级别等。 - 引入映射文件或映射包。 ##### 4. 第一段代码 - **简单示例**: - 创建一个实体类,定义属性和getter/setter方法。 - 编写一个DAO接口和实现类,使用...

Global site tag (gtag.js) - Google Analytics