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
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 苹果手机浏览器横屏怎么办 苹果笔记本浏览器没有了怎么办 剑与家园魔镜带错兵怎么办 橙子vr上下反了怎么办 我的恐龙手机不支持ar怎么办 被小人陷害又无计可施怎么办 蚂蚁借呗2万逾期怎么办 蚂蚁借呗还款金额受限怎么办 蚂蚁借呗不能借钱了怎么办 美柚手机号换了怎么办 美柚他他圈被禁言了怎么办? 被蝎子蜇了屁股怎么办 被蝎子蛰了该怎么办 孕妇让蝎子蛰了怎么办 脸被蝎子蛰了怎么办 皮肤看着有点老怎么办 王者铭文被卖了怎么办 游戏cp送我皮肤怎么办 消防改革武警学院的学员怎么办 几把毛掉的厉害怎么办 从公务员调入事业单位的怎么办 电车被城管扣了怎么办 超变战陀发射器绳坏了怎么办 家里人总打击我怎么办干啥都要骂 欧陆风云4破产后怎么办 车被别人喷了漆怎么办 龙分期绑银行卡维护钱还不上怎么办 去维和要是伤了怎么办 头盔镜片刮花了怎么办 小牛u1钥匙丢了怎么办 非牛顿流体干了怎么办 刺激战场0信誉分怎么办 假如非牛顿干了怎么办? 退出id后照片了怎么办 小麦收割机麦糠有籽粒怎么办 在家带娃没钱花怎么办 看3d电影近视的怎么办 摩托车电瓶没电了怎么办 踏板摩托车电瓶没电了怎么办 摩托车离合油没了怎么办 论文数据计算错误该怎么办