zoukankan      html  css  js  c++  java
  • hibernate 学习笔记3

    1. 多对多关联:

    在双方都要用一个类型为Set的属性保存对方的信息,并在映射配置文件中指定这个属性的名字,并指定中间表。还需要通过<key column=””>来指定自己在中间表中对应的外键。在<many-to-many>标签中,要配置对方的类,并且指定对方类在中间表中的对应的外键

    *学生表配置文件:

        <class name="edu.whu.swe.lxl.learn.hibernate.model.stucourse.Student" table="student" schema="dbforlearn">

            <id name="id" column="id" >

                <generator class="native"/>

            </id>

            <property name="num" column="num"/>

            <property name="name" column="name"/>

            <!--配置set集合描述类Student中的courses属性和中间表信息-->

            <set name="courses" table="stu_course" >

                <!--设置本类在连接表中对应的外键-->

                <key column="student"/>

                <!--配置关联类以及关联类在中间表中的外键-->

                <many-to-many class="edu.whu.swe.lxl.learn.hibernate.model.stucourse.Course"

                              column="course"/>

            </set>

    </class>

    *课程表的映射文件:
        <class name="edu.whu.swe.lxl.learn.hibernate.model.stucourse.Course" table="course" schema="dbforlearn">

            <id name="id" column="id">

                <generator class="native"

            </id>

            <property name="num" column="num"/>

            <property name="name" column="name"/>

            <!--配置关联类在本类中对应的属性以及中间表-->

            <set name="students" table="stu_course">

                <!--设置本类在连接表中对应的外键-->

                <key column="course"/>

                <!--配置关联类以及关联类在中间表中对应的外键-->

                <many-to-many class="edu.whu.swe.lxl.learn.hibernate.model.stucourse.Student"

                              column="student"/>

            </set>

        </class>

    *一般在多对多关系中,不存在级联删除的需求。在多对多中,千万不要加入cascade=delete,否则会是灾难性的。

    2.查询

    1)唯一标识OID的检索方式(重要)

    Session.get(obj.class,OID)

    2) 对象的导航方式(重要)

    一对多查询时,利用里面包含的set

    3)HQL的检索方式(重要)

    Hibernate Query Language  ——hibernate的查询语言

    4)QBC的检索方式(重要)

    Query By Criteria  ——条件查询

    5)SQL查询

    3.HQL查询

    * HQL是面向java对象的,和SQL有相似之处

    *是hibernate中使用最广泛的检索方式

    *hibernate负责解析HQL,然后根据ORM配置的映射关系,生成相应的SQL语句

    *HQL操作的是类以及属性,而不是数据表和字段

    4.延迟加载技术——在class标签上配置

    1)延迟加载先获取到代理对象,当真正使用到该对象中的属性且缓存里没有值时,才会发送SQL语句,是hibernate框架提升性能的主要方式。

    2)类级别的延迟加载

    *Session对象的load方法默认就是延迟加载

    *Customer c=session.load(Customer.class,1L),没有发送SQL语句,当使用该对象的属性时,才发送SQL语句

    【实例】

        /**

           <class name="edu.whu.swe.lxl.learn.hibernate.model.Customer" table="customer" >

            <id name="id" column="id">

                <generator class="identity"/>

            </id>

            <property name="name" column="name"/>

            <property name="address" column="address"/>

            <property name="age" column="age"/>

            <property name="registerDate" column="register_date"/>

        </class>     */

       public void testLoad(){

            Customer customer = session.load(Customer.class, 3);

            log.trace(customer.getId().toString());//没有发送SQL,因为ID已经由代码提供了,此时开始变成持久态

            log.trace("+++++++++++++++++");

            log.trace(customer.getName());//发送SQL语句,因为此时缓存里没有name信息,必须要发送SQL从数据库中查询

        }

    *使类级别的延迟加载失效:

        **在<class>标签上配置lazy=”false”

        **Hibernate.initialize(Object proxy)

    【实例】

    /**

         <class name="edu.whu.swe.lxl.learn.hibernate.model.Customer" table="customer" lazy="false">

         <id name="id" column="id">

         <generator class="identity"/>

         </id>

         <property name="name" column="name"/>

         <property name="address" column="address"/>

         <property name="age" column="age"/>

         <property name="registerDate" column="register_date"/>

         </class>

         */

        @Test

        public void testLoadNotLazy() {

            Customer customer = session.load(Customer.class, 3);

            log.trace(customer.getId().toString());//没有发送SQL,因为ID已经由代码提供了,此时开始变成持久态

            log.trace("+++++++++++++++++");

            log.trace(customer.getName());//发送SQL语句,因为此时缓存里没有name信息,必须要发送SQL从数据库中查询

        }

    3)关联级别的延迟加载。

    * CustCustomer customer=session.get(CustCustomer.class,1L)不是延迟加载,但是它不会把代理类CustCustomer的关联类CstLinkman加载进来,当使用CstLinkman linkmans=customer.getLinkmans()获取关联类对象的时候,因为没有用到CstLinkman的任何属性,也不需要知道有几个linkman,所以还是不会加载。直到使用了linkmans里的属性时,才会发送SQL加载关联类对象。

    【实例】

            /**

             * <set name="linkMans" cascade="delete-orphan" inverse="true">

             <!--外键-->

             <key column="lkm_cust_id"/>

             <!--对应关系-->

             <one-to-many class="edu.whu.swe.lxl.learn.hibernate.model.CstLinkman" />

             </set>

             */

            CustCustomer customer = session.get(CustCustomer.class, 19L);//直接发送SQL查询CustCustomer,但不查询CstLinkman

            log.trace(customer.getCustId().toString());//

            log.trace("++++++++++++++++++++++++++");

            Set linkmans=customer.getLinkMans();//还是不发送SQL,因为还没有必要查询CstLinkman的属性

            log.trace("++++++++++++++++++++++++++");

            log.trace(""+linkmans.size());//这个时候发送SQL,因为不发送,就不知道有几个linkman了。

    5.延迟加载技术——在set标签上配置策略

    1)在<set>标签上使用fetch和lazy属性

    *fetch的取值       ——控制SQL语句的生成格式

        ** select       ——默认值,发送查询语句

        **join            ——连接查询,发送的是一条左外链接查询,此时,关联表延迟加载失效(因为不需要再发起一次SQL查询关联表了,而是在一次外链接查询中完成了所有表的加载)

        **subselect    ——子查询,发送一条子查询完成关联对象的查询。(需要使用list()方法进行测试,如Criteria.list()或者Query.list())

    *lazy的取值        ——查询关联对象的时候是否采用延迟加载

        **true         ——默认,延迟

        **false         ——不延迟

        **extra         ——极其懒惰,根据需要查询,而不是查询所有字段,比如用一写聚合函数,或者只查询某一个字段

    一般都采用默认值即可

    【示例】

    *fetch=”join”

    public void testJoinSet(){

            /**

             <set name="linkMans" cascade="delete-orphan" inverse="true" fetch="join>

             <!--外键-->

             <key column="lkm_cust_id"/>

             <!--对应关系-->

             <one-to-many class="edu.whu.swe.lxl.learn.hibernate.model.CstLinkman" />

             </set>

             */

            CustCustomer customer = session.get(CustCustomer.class, 19L);//直接发送join SQL 左外连接查询,一次性获取所有的数据

            log.trace(customer.getCustId().toString());

            log.trace("++++++++++++++++++++++++++");

        }

    *fetch=”select” lazy=”extra”

        @Test

        public void testExtraLazy() {

            /**

             <set name="linkMans" cascade="delete-orphan" inverse="true" fetch="select" lazy="extra">

             <!--外键-->

             <key column="lkm_cust_id"/>

             <!--对应关系-->

             <one-to-many class="edu.whu.swe.lxl.learn.hibernate.model.CstLinkman" />

             </set>

             */

            CustCustomer customer = session.get(CustCustomer.class, 19L);//直接发送SQL查询CustCustomer,但不查询CstLinkman

            log.trace(customer.getCustId().toString());//

            log.trace("++++++++++++++++++++++++++");

            Set linkmans = customer.getLinkMans();//还是不发送SQL,因为还没有必要查询CstLinkman的属性

            log.trace("++++++++++++++++++++++++++");

            log.trace("" + linkmans.size());//发送select count(lkm_id) form cst_linkman where lkm_cust_id=?,而不是查询所有字段

        }

    *fatch=”subselect”

        public void testSubselectSet() {

            /**

             <set name="linkMans" cascade="delete-orphan" inverse="true" fetch="subselect">

             <!--外键-->

             <key column="lkm_cust_id"/>

             <!--对应关系-->

             <one-to-many class="edu.whu.swe.lxl.learn.hibernate.model.CstLinkman" />

             </set>

             */

            Query query = session.createQuery("from CustCustomer ");

            List<CustCustomer> customers = query.list();//发送SQL查询CustCustomer,但不查询CstLinkman

            log.trace("++++++++++++++++++++++++++++++++++");

            for(CustCustomer customer:customers){

                Set linkmans

                        = customer.getLinkMans();//不发送SQL

                log.trace("++++++++++++++++++++++++++++++++++");

                log.trace(""+linkmans.size());//在第一次循环时候,就发送子查询把List所有中所有用户的所有联系人都一次性查询出来,下次循环就不用发送SQL了。如果不适用subselect,那么循环一次,就发送一次SQL查询该客户的联系人

            }

        }

    6.优化技术——在<many-to-one>标签中配置策略

    1)在<many-to-one>标签上使用fetch和lazy属性

      *fetch的取值                            ——控制SQL语句的格式

          **select                   ——默认,发送基本的select语句查询

          **join                            ——无效,所以fetch只能是select,所以不用设置fetch

      *lazy的取值

          **false                                   ——不采用延迟加载

               **proxy                         ——默认值,是否延迟加载取决于一方set 标签的lazy取值,多方和一方的lazy值一样。

    7.当fetch=select,lazy=true的时候,使用list时,对从表的查询是一次循环获取进行一次的,此时如果不想设置subselect进行子查询,那么可以设置set标签的batch-size=10,从而达到批量获取从表数据的目的。当设置batch-size=10时,hibernate会一次就取10个客户的联系人。具体工作原理这样的:

    1)先获取所有的客户

    2)再用select xxx xxx xxx from cst_linkman where cst_linkman.lkm_cust_id in( 10个客户的id  )批量获取10个客户的联系人。

    总结:session.load采取的是类级别的延迟加载,并且在class标签上配置当前类的延迟加载策略;session.get采取的是连接上的延迟加载,并且在set标签上配置加载策略,在many-to-one上也可以进行配置。

    8.延迟加载策略的优缺点及适用范围:
    1)有点

    有应用程序决定要加载哪些对象,可以避免执行多余的SQL语句,避免加载不程序不会访问的对象,提高性能和空间利用率。

    2)缺点

    应用程序如果试图访问处于游离态的代理类实例,必须保证它在持久化状态是已经被初始化了。而延迟加载策略往往导致代理类实例相应的set没有值,从而需要把游离态对象通过session.update方法变成持久态,再去访问set中的对象从而加载对象。

    3)适用范围

    ——一对多或者多对多

    ——应用程序不需要立即访问或者根本不需要访问的对象。

    9.在配置文件中配置的加载策略影响全局,但是应用程序的需求可能是多样的,在不同的时候需要不同的加载策略,因此,hibernate提供了在应用程序中指定加载策略的方式,应用程序中指定的加载方式将覆盖配置文件中的加载方式(局部优先于整体原则)

    10.一对一的加载默认是使用左外连接查询。

  • 相关阅读:
    UIView的常见属性
    Object-C-Foundation-反射
    Object-C-自定义类型归档
    Java集合:HashMap源码剖析
    spring-boot-2.0.3之quartz集成,数据源问题,源码探究
    杂谈篇之我是怎么读源码的,授之以渔
    ElasticSearch 从零到入门
    java实现图片上传功能,并返回图片保存路径
    quartz定时任务及时间设置
    笛子初学者吹什么曲子
  • 原文地址:https://www.cnblogs.com/JMLiu/p/10178425.html
Copyright © 2011-2022 走看看