Hibernate检索策略
来源:互联网 发布:淘宝代刷信誉平台 编辑:程序博客网 时间:2024/06/05 03:23
Hibernate检索策略
它是为了让我们的查询更加的有效率,是优化我们查询用的。 它是靠配置的方式来实现的
延迟加载
延迟加载(lazy load)是(也称为懒加载 )Hibernate关联关系对象默认的加载方式,延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。
通常将延迟加载分为两类 :一类叫做类级别延迟 ,另一类叫做关联级别的延迟。类级别的延迟指的是查询某个对象的时候,是否采用有延迟,这个通常在<class>标签上配置lazy属性。关联级别的延迟指的是,查询一个对象的关联对象的时候是否采用延迟加载。这个通 常在<set>或<many-to-one>上配置lazy属性。
类级别的延迟加载
使用load方法检索某个对象的时候,这个类是否采用延迟加载的策略,就是类级别的延迟。类级别的延迟一般在<class>上配置lazy属性,lazy的默认值是 true 。默认是延迟加载的 ,所以使用 load方法去查询的时候 ,不会马上发送SQL语句。当真正使用该对象的时候,才会发送SQL语句。
Customer customer = session.load(Customer.class,1L);
其实如果不想使用延迟加载也有很多种方法,当然最简单的就是将这个类的映射文件上的lazy设置为false,当然也可以将这个持久化类改为final修饰,如果改为final修饰的话。就无法生成代理类,就会使延迟加载失效。
这是类级别的延迟加载,类级别的延迟加载一般不进行修改 ,采用默认值 lazy="true"就可以了。
关联级别的延迟加载
关键级别的延迟加载指的是查询到某个对象以后,检索它的关联对象的时候是否采用延迟加载 。
Customer customer = session.get(Customer.class,1L);Set<LinkMan> linkMans = customer.getLinkMans();
通过客户查询其关联的联系人对象,在查询联系人的时候是否采用延迟加载称为是关联级别的延迟。关联级别的延迟通常是在<set>和<many-to-one>上来进行配置 。
<set>标签上的lazy通常有三个取值 :
- true : 默认值,采用延迟加载
- false: 检索关联对象 的时候,不采用延迟加载 。
- extra : 极其懒惰的,用到什么加载什么。
<many-to-one>标签上的 lazy 通常有三个取值:
- proxy:默认值,是否采用延迟取决于一的一方类上的lazy属性的值 。
- false:检索关联对象的时候,不采用延迟加载。
- no-proxy: 不用研究。
关联级别的抓取策略
抓取策略指的是查询到某个对象的时候,如何抓取其关联对象。这个也可以通过配置完成 。在关联对象的标签上配置fetch属性。关联上就分为是在<set>和<many-to-one>上,也都有不同的取值 。
<set>标签上的fetch通常有三个取值:
- select:默认值,发送的是普通的 select 语句查询。
- join:发送一条迫切左外连接去查询。
- subselect:发送一条子查询语句查询其关联对象。
<many-to-one>标签上的 fetch 有两个取值 :
- select:默认值,发送一条普通的select 语句查询关联对象。
- join:发送一条迫切左外连接语句查询其关联对象。
set上配置fetch有三个值,lazy有三个值,这样就会产生很多种的效果。其实不用担心,因为fetch如果设置为join,lazy就会失效了。
简单的总结一 下fetch和lazy的作用,其实fetch主要控制抓取关联对象的时候的发送SQL语句的格式的。lazy主要控制查询其关联对象的时候是否采用延迟加载的。
批量抓取
在抓取的策略中有一种叫做批量抓取,就是同时查询多个对象的关联对象的时候,可以采用批量抓取进行优化 。当然这不是特别的重要。如果要实现批量的抓取效果,可以通过配置batch-size来完成。
可以在class和set上配置
- 在一的那方的class配置,表示在查询多方时可以同时获取几个一方的对象。
- 在一的那方的set上配置,表示在查询一方时可以同时获取几个多方的对象。
实际开发中推荐的取值
一对多(多对多)的情况:
lazy:true
fetch:select
多对一的情况:
lazy:false
fetch:select
一对多(多对多)情况
序号
lazy的取值
fetch的取值
说明(都是以客户订单的一对多关系为例)
1
true(默认值)
select(默认值)
时机:用时才真正去查询订单。
语句形式:有1条查询客户的和多条查询订单的select语句。
batch-size:设置批量检索的深度。(建议3~10之间)
2
false
select(默认值)
时机:不管用不用订单,查询客户时都立即查询订单。
语句形式:有1条查询客户的和多条查询订单的select语句。
batch-size:设置批量检索的深度。(建议3~10之间)
3
extra
select(默认值)
时机:用什么信息,查什么信息。只查询必要的。
语句形式:有1条查询客户的和多条查询订单的select语句。
batch-size:设置批量检索的深度。(建议3~10之间)
4
true
subselect
时机:用时才真正去查询订单。
语句形式:子查询
batch-size:无效
5
false
subselect
时机:不管用不用订单,查询客户时都立即查询订单。
语句形式:子查询
batch-size:无效
6
extra
subselect
时机:用什么信息,查什么信息。只查询必要的。
语句形式:子查询
batch-size:无效
7
true|false|extra
join(当join有效时,根本不看lazy属性)
时机:无效。因为连接查询,一次就是两张表及以上。
语句:left outer join
batch-size:无效
注意:Query查询会忽略join的存在。当join无效时,lazy就有效了。
多对一(一对一)情况
序号
lazy的取值
fetch的取值
说明(都是以客户订单的一对多关系为例)
1
proxy
select
时机:
对象类级别的策略:true。
延迟加载。得到的是代理对象。
对象类级别的策略:false。
立即加载。得到就是类对象。
语句:
多条SQL语句
2
false
select
时机:立即加载。与对象类级别的策略无关。
语句:多条SQL语句。
3
true|false|extra
join(当join有效时,根本不看lazy属性)
时机:无效。因为连接查询,一次就是两张表及以上。
语句:left outer join
batch-size:无效
注意:Query查询会忽略join的存在。当join无效时,lazy就有效了。
测试Hibernate检索策略
package com.pc.hibernate.test.querystrategy;import java.util.List;import org.hibernate.Query;import org.hibernate.Session;import org.hibernate.Transaction;import org.junit.Test;import com.pc.hibernate.domain.Customer;import com.pc.hibernate.domain.LinkMan;import com.pc.hibernate.utils.HibernateUtils;/** * Hibernate的检索策略 * 明确: * 它是为了让我们的查询更加的有效率,是优化我们查询用的。 * 它是靠配置的方式来实现的。 * 关联级别的检索策略关心的是: * 实体类中的那个关联对象。 * 例如: * 客户实体类中,关心的是联系人 * 联系人实体类中,关心的是客户 * 用户实体类中,关心的是角色 * 角色实体类中,关心的是用户 * 类级别检索策略关心的是: * 是当前实体类中所对应数据库表中所包含字段。 * 类级别解决的问题: * 什么时候真正去查询,查询实体类中除了OID外的其他字段信息。 * * 关联级别的检索策略解决的问题:(从哪些方面优化) * 1、查询的时机: * 到底什么时候真正的去查询 * 立即加载 * 延迟加载:惰性加载,懒加载 * 2、采用什么方式去查询 * 多条SQL语句 * 子查询 * 表连接 * 关联级别的检索策略分几种情况: * 分为两种情况: * 一对多和多对多: * 有少的一方,根据少的一方获取多的一方。 * 多对一和一对一 * 有多的一方,根据多的一方获取少的一方。 * 关联级别涉及的配置 * 一对多(多对多)情况: * 涉及的标签:set * 涉及的属性:lazy:什么时候去查询 * 取值: * true:延迟加载(默认值) * false:立即加载 * extra:极懒加载 用什么数据,查什么数据,不用的都不查 * fetch:用什么方式去查询 * 取值: * select:多条SQL语句(默认值) * subselect:子查询 * join:表连接 * 多对一(一对一)情况: * 涉及的标签:many-to-one * 涉及的属性:lazy:什么时候去查询 * false:立即加载 * proxy:看关联对象的类级别检索策略 * no-proxy:不用管,实际开发根本不用 * fetch:用什么方式去查询 * select:多条SQL语句 * join:表连接 * * * 实际开发中: * 一对多(多对多)的情况: * lazy:用true * fetch:用select * 多对一的情况: * lazy:false * fetch:select * * @author Switch * */public class TestQueryStrategy1 { /** * 需求: * 查询id为1的客户下的所有联系人 * 查询的时机: * 延迟加载 * 查询的方式: * 多条语句。2条,一条查询了客户,一条查询了联系人 */ @Test public void test1(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); //1.查询id为1的客户 Customer customer = session.get(Customer.class, 1L); //2.使用对象导航查询,查询该客户的联系人 //类级别检索策略 System.out.println(customer); System.out.println(customer.getLinkMans().size()); //关联级别检索策略 System.out.println(customer.getLinkMans()); tx.commit(); } /** * 需求: * 查询所有客户,获取每个客户的联系人 * 查询的时机 * 延迟加载 * 查询的方式 * 多条语句。5条SQL语句。查询联系人只有4条语句,还有一条是查询客户的。 * Hibernate的N+1问题: * 当我们查询一个从表关联对象集合时,正常查询应该是N条语句,但是由于需要查询主表,所以会多出一条语句。 * 解决N+1问题: * 在Hibernate的映射配置文件中,添加一个batch-size属性。该属性的含义:批量抓取。简单的说就是问号的个数。 * batch-size属性的取值:建议3~10之间。 */ @Test public void test2(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); //1.查询所有客户 Query query = session.createQuery("from Customer"); @SuppressWarnings("unchecked") List<Customer> customers = query.list(); for (Customer customer : customers) { //2.使用对象导航查询,查询该客户的联系人 //类级别检索策略 System.out.println(customer); //关联级别检索策略 System.out.println(customer.getLinkMans()); } tx.commit(); } /** * 需求: * 查询id为1的联系人的所属客户 * 查询的时机:false * 立即加载 * 查询的方式:select * 多条语句 */ @Test public void test3(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); //1.查询id为1的联系人 LinkMan l1 = session.get(LinkMan.class, 1L); //2.使用对象导航查询,获取该联系人的客户 System.out.println(l1); System.out.println(l1.getCustomer()); tx.commit(); } /** * 需求: * 查询id为1的联系人的所属客户 * 查询的时机:proxy * 看关联对象的类级别检索策略 * 查询的方式:select * 多条语句 */ @Test public void test4(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); //1.查询id为1的联系人 LinkMan l1 = session.get(LinkMan.class, 1L); //2.使用对象导航查询,获取该联系人的客户 System.out.println(l1); System.out.println(l1.getCustomer()); tx.commit(); }}
Customer.hbm.xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><!--1、导入dtd约束 在Hibernate的核心jar包中:hibernate-mapping-3.0.dtd2、编写配置文件 实体类和数据库表的对应关系 实体类中属性和表的字段的对应关系 --><hibernate-mapping package="com.pc.hibernate.domain"> <!-- class标签: 作用:用于配置实体类和表之间的对应关系 属性: name:实体类的名称。它应该写全限定类名 table:数据库表的名称 --> <class name="Customer" table="cst_customer" lazy="true" batch-size="3"> <!-- id标签: 作用:映射主键 属性: name:实体类的属性名称 column:数据库表的字段名称 type:主键的类型 --> <id name="custId" column="cust_id" type="java.lang.Long"> <!-- generator标签: 作用:主键的生成方式 属性: class:指定方式 取值:native 含义:使用本地数据库的自动增长能力。 --> <generator class="native"/> </id> <!-- property标签: 作用:映射其他字段 属性: name:实体类的属性名称 column:数据库表的字段名称 type:字段的类型 length:数据库中对应列的长度 --> <property name="custName" column="cust_name" type="java.lang.String" length="32"/> <property name="custSource" column="cust_source" type="java.lang.String" length="32"/> <property name="custIndustry" column="cust_industry" type="java.lang.String" length="32"/> <property name="custLevel" column="cust_level" type="java.lang.String" length="32"/> <property name="custAddress" column="cust_address" type="java.lang.String" length="128"/> <property name="custPhone" column="cust_phone" type="java.lang.String" length="64"/> <!-- 配置一对多 --> <set name="linkMans" inverse="false" cascade="save-update" batch-size="4" lazy="true" fetch="select"> <key column="lkm_cust_id" /> <one-to-many class="LinkMan"/> </set> </class></hibernate-mapping>
LinkMan.hbm.xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.pc.hibernate.domain"> <class name="LinkMan" table="cst_linkman"> <id name="lkmId" column="lkm_id" type="java.lang.Long"> <generator class="native" /> </id> <property name="lkmName" column="lkm_name" type="java.lang.String" length="16"/> <property name="lkmGender" column="lkm_gender" type="java.lang.String" length="10"/> <property name="lkmPhone" column="lkm_phone" type="java.lang.String" length="16"/> <property name="lkmMobile" column="lkm_mobile" type="java.lang.String" length="16"/> <property name="lkmEmail" column="lkm_email" type="java.lang.String" length="64"/> <property name="lkmPosition" column="lkm_position" type="java.lang.String" length="16"/> <property name="lkmMemo" column="lkm_memo" type="java.lang.String" length="512"/> <!-- 配置多对一 --> <many-to-one name="customer" class="Customer" column="lkm_cust_id" cascade="save-update" lazy="proxy" fetch="select"/> </class></hibernate-mapping>
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><!-- 1、导入dtd约束 在hibernate核心jar包中:hibernate-configuration-3.0.dtd 2、编写配置文件 --><hibernate-configuration> <!-- 配置SessionFactory --> <!-- 创建SessionFactory需要3部分信息。 而配置文件中要写哪些配置,我们可以翻阅资料。 --> <!-- 第一部分:连接数据库的基本信息,第二部分:hibernate的基本配置,第三部分:映射文件的位置 --> <session-factory> <!-- 1、连接数据库的基本信息 --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mycrm</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">123456</property> <!-- 数据库的方言 --> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 2、hibernate的基本配置 --> <!-- 是否显示SQL语句 --> <property name="hibernate.show_sql">true</property> <!-- 是否格式化显示SQL语句 --> <!-- <property name="hibernate.format_sql">true</property> --> <!-- 采用何种策略来创建表结构: --> <!-- update:检查表结构和实体类映射文件的变化,如果发现映射文件和表结构不一致,更新表结构。 --> <!-- 注意:hibernate不能创建数据库,只能在有数据库的情况下创建表结构。 --> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 配置hibernate使用连接池:告知Hibernate使用连接池的厂商 --> <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property> <!-- 配置把Session绑定到当前线程上,从而保证一个线程只有一个Session --> <property name="hibernate.current_session_context_class">thread</property> <!-- 3、映射文件的位置 --> <mapping resource="com/pc/hibernate/domain/Customer.hbm.xml" /> <mapping resource="com/pc/hibernate/domain/LinkMan.hbm.xml" /> </session-factory></hibernate-configuration>
0 0
- Hibernate的检索策略
- Hibernate的检索策略
- Hibernate的检索策略
- hibernate检索策略
- hibernate检索策略1
- Hibernate 检索策略
- Hibernate中检索策略
- Hibernate检索策略总结
- Hibernate的检索策略
- Hibernate检索策略
- Hibernate的检索策略
- hibernate的检索策略
- Hibernate的检索策略
- Hibernate检索策略
- Hibernate 检索策略
- hibernate中的检索策略
- Hibernate检索策略
- Hibernate配置---检索策略
- Spring createBean过程中BeanPostProcessor的处理机会
- 【玩转SQLite系列】(五)SQLite数据库优化
- pat甲1011. World Cup Betting(水题)
- 指针
- Big Event in HDU-01背包(dp思想)
- Hibernate检索策略
- JDBC层次结构和基本构成
- 数据库(二)关系数据库
- Python计算机视觉:对图片进行格式转换
- 内存泄漏分析
- React Native android release 发布
- 基于ODPS的SQL语句
- Supervised Descent Method and its Applications to Face Alignment(SDM)
- 汇编 标志寄存器和标志位