Hibernate总结

来源:互联网 发布:大逃杀cmd重置网络 编辑:程序博客网 时间:2024/05/22 15:48

1`hibernate的定义

  1. 是一个持久层框架
  2. 是一个ORM框架
  3. 对jdbc的封装(记忆)
  4. 用面向对象的思想,操作关系型数据库。(体会)

2`hibernate的配置文件:

映射文件

  1. class标签

    处理类与表的映射关系 name: 类的全路径名称table:对应的表的名称(如果与类名形同,可以省略)catalog: 指定表所在的数据库

【实战】name,table

  1. id标签

    处理主键字段的映射关系name:主键对应的类中属性的名字column:表中主键的名字type:类型,指定字段的类型,表达方式有两种:java方式,hibernate方式  举例:类型是整型: java: java.lang.Integer  hibernate: integerlength: 长度,指定字段的长度。(在自动建表的时候,才会体现)

【实战】name,column

  1. property

    处理普通字段的映射关系 name:类中属性的名字
    column:表中字段的名字type:类型,指定字段的类型,表达方式有两种:java方式,hibernate方式  举例:类型是整型: java: java.lang.Integer  hibernate: integerlength: 长度,指定字段的长度。(在自动建表的时候,才会体现)
    not-null: 非空约束(自动建表的时候,体现)unique: 唯一约束(自动建表的时候,体现)

【实战】name,column

3`核心配置文件(hibernate.cfg.xml)

  1. 连接数据库的参数配置
    • 名称的来由(连接数据库的那些配置从哪找):hibernate-release-5.0.7.Final\project\etc\hibernate.properties
  2. 自身的参数

    • 必选:方言配置

    • 指定底层的数据库。针对性的生成对应的SQL,从而实现跨数据库特性。

    • 跨数据库:用mysql, 切换成oracle.
    • 不同的数据库,SQL语句存在不同(部分不同,大部分相同的)
    • 最典型的例子:分页:select * from user limit 5,5;
    • oracle: 特别复杂。select * from (select rowid as num , a.* from user a where rowid <10) b where num >5;

    • 可选:

    • 显示sql语句

    • 自动建表

    • 工作中,一般使用none, validate。

      <!-- 可选:是否自动建表none:默认值create:启动时,自动建表(测试)create-drop:启动时,自动建表,关闭时,自动销毁表(测试)update:没有表的时候,自动建表。有表,使用原来的表。如果表结构不匹配,更新表结构(测试)validate:不会自动建表。如果有表,检查表的结构,如果,不匹配,报错。--><property name="hibernate.hbm2ddl.auto"></property>
    * 加载映射文件            <mapping resource="cn/itcast/domain/Customer.hbm.xml"/> 

【实战】

  • 自动建表:一般配置成none(默认值)
  • 重点理解:方言的作用

4`持久化类的编写规则

  • 有无参的构造方法。
    • hibernate通过反射来创建持久化类的实例对象。
  • 属性私有化,对属性提供get/set方法。
    • java的要求,属性私有化。hibernate,要封装数据,要求get/set方法。
  • 属性尽量使用包装类。
    • 不使用基本类型。因为,包装类和基本类型的初始化值不同。java.lang.Integer: null, int :0. –>在数据库中,null值和0值的不同。
  • 持久化类要有一个唯一标识OID与表的主键对应。
    • java区分是否同一个对象的方法:对象的地址是否相同。持久化类区分是否同一个对象的方法:oid值是否相同。
  • 持久化类,不要使用final修饰符。
    • final修饰符,修饰的类,是不能被继承的。load方法,提供延迟加载功能,延迟加载的机制:依赖于目标类(持久化类)通过继承生成的代理对象。使用final修饰后,没有办法生成代理对象,导致延迟加载失效。

5`hibernate持久化类的状态

持久化类的三种状态

  1. hibernate为了更好的管理持久化类。给持久化类分为三种状态。

  2. 回顾什么是持久化类。

    1. 持久化类的三种状态是:

      • 瞬时状态(Transient): 没有oid,没有关联session对象
      • 持久状态(Persistent):有oid, 关联session对象
      • 托管状态(Detached): 有oid, 没有关联session对象

    持久化类中持久态的特性(重点理解)

    • 自动更新数据库

    【总结】

    • session内部,有两个存储区:一个是一级缓存区,一个是快照区
    • 持久化类在持久状态下,进行的修改,只会修改缓存区的数据。快照区的数据,一致保持和数据库的原始数据一致。
    • 当事务提交的时候,对比一级缓存区和快照区,如果一致,说明,数据与数据库的原始数据一致,无需update。如果,不一致,说明需要进行update修改。

6`hibernate的主键策略

  1. 数据库主键的分类
    • 自然主键:对象本身的属性,作为表的主键
    • 代理主键:不使用对象本身的属性,而使用没有任何意义的一个字段,作为主键。(推荐)
  2. hibernate提供的主键生成策略
    • increment:适合代理主键,适用于int,short,long(整型)。由hiberante提供,原理:先查询select max(id) from user ,+1 作为新记录的主键值。 缺陷:在多线程、集群环境中,不能使用。
    • indentity:适合代理主键,适用于int,short,long(整型)。由底层数据库实现,要求支持自增长类型(auto_increment),例如:mysql。
    • sequence:适合代理主键,适用于int,short,long(整型)。由底层数据库实现,要求支持序列,例如:oracle.
    • native:适合代理主键,适用于int,short,long(整型)。特点:本地化,根据底层数据库支持的类型不同,采取不同的策略。如果,底层数据库支持自增长类型,native相当于indentity; 如果,底层数据库支持序列,natvie相当于sequence.实现跨数据源的特性(推荐)
    • uuid:适合代理主键,支持字符串。(一般不使用)
    • assigned:默认值,适合自然主键,主键的值,要求程序手动输入。

7`缓存

什么是缓存(面试题)

  1. 英文资料描述:缓存就是存贮数据(使用频繁的数据)的临时地方,因为取原始数据的代价太大了,所以我可以取得快一些。
  2. 个人理解:缓存理解成一种策略。利用高速存储区域的空间,提高对低速存储区域数据的读取速度。即空间换时间。
  3. 生活中的类似的场景:我们最经常使用的物品,放在最显眼的地方。把最常穿的衣服,挂载衣柜,不常穿的,放在箱子。

缓存的原理

  • 利用高速存储区域,保存低速存储区域的数据,从而提供缓存功能。
  • 考虑三层:cpu–内存–硬盘

hibernate一级缓存:定义和存在的依据

  1. hibernate的缓存分为两个级别:一级缓存和二级缓存。

    • 一级缓存: session级别的缓存,自带的不可卸载。一级缓存的生命周期与session一致。
    • 二级缓存:SessionFactory级别的缓存,不是自带的需要进行配置才能使用的。二级缓存的生命周期与SessionFactory一致。不过,实际中,用redis代替二级缓存,故不使用。
  2. hibernate缓存的原理

    • 通过OID来区分持久化对象。OID相同,认为是同一个持久化对象。
    • hibernate调用get/load进行查询时,先查询一级缓存,通过OID区分,如果该持久化对象存在,直接使用,不发送SQL语句。如果,不存在,就发送SQL语句,并且把查询到的持久化对象,保存到缓存中。
    • hibernate调用save(),update()等操作,都一样。

8`hibernate的事务管理

hibernate设置的隔离级别

  1. 每个数据库连接都有默认的隔离级别,通常是读已提交或可重复读.可以通过数据库配置设置,也可在应用程序中设置。例如Hibernate:在hibernate.cfg.xml中设置隔离级别:

    1—Read uncommitted isolation:读未提交2—Read committed isolation:读提交4—Repeatable read isolation:重复读8—Serializable isolation:序列化<!-- 事务隔离级别 --><property name="hibernate.connection.isolation">2</property>

hibernate的事务管理代码

​ 在hibernate.cfg.xml中配置:

<!-- 配置session绑定本地线程 --><property name="hibernate.current_session_context_class">thread</property>
  • hibernate的sessionFactory提供getCurrentSession()创建一个session和ThreadLocal绑定方法。

9`javaBean如何表达表与表的关系

  1. java类如何表达:1对多

    • 使用实际的场景分析:部门和员工,典型的:1对多关系。

    • java(使用面向对象的观点)如何表达:1对多

      class Department{    Integer  id;    String   name;        Set<Employee>  employees = new HashSet<Employee>();  }  class Employee{    Integer  id;    String   name;    Department department; // 部门的对象
         }  
  2. 表达多对多

     class Student{Integer  id;String   name;Set<Course> courses = new HashSet<Course>(); } class Course{Integer  id;String    name;    Set<Student> students=new HashSet<Student>(); }  

10`一对多配置映射文件

hibernate:1对多之建立关系(双向1对多)

  1. 数据库:增加外键约束.

      alter table 表名  add column 字段名  类型;
        alter table 从表名 add foreign key(外键字段) references 主表名(主键字段);
  2. java类的表达

  3. hbm.xml映射文件的表达(重点)

      // 1的这方对应的持久化的类的配置:   set标签:一的这方,保存多的这方,使用的是set集合。        name: 持久化类中属性的名字   key标签:column:  外键的字段名称   one-to-many标签:从一的一方出发,寻找多的一方的数据。class:找到的数据,需要封装成那个类的对象的全路径名称<set name="employees">    <key column="e_did"></key>    <one-to-many class="cn.itcast.domain.Employee"/></set>
【记忆的方式
 * 思考查询:现在从部门,查找这个部门所有的员工  * key:查找的关键,根据外键的值,去寻找。  * one-to-many: 表示方向,从一的一方找多的一方。class表达了找到的结果,需要封装的类型
        // 多的一方:         name: 类中属性的名称         class:需要封装的类的全路径名称         column: 外键的名称        <many-to-one name="department" class="cn.itcast.domain.Department"  column="e_did"></many-to-one>

【记忆的方式】

  • 思考查询:已知员工信息,寻找员工对应的部门
  • many-to-one:表达方向,从多的一方去寻找一的一方。class: 找到的数据,需要封装的类型。 column: 寻找的依据,根据什么数据来找

11`级联cascade

  1. 级联的配置:(1对多)

    • 映射文件中,和都可以配置级联属性:cascade
  2. 级联的常见取值

    none:        默认值。所有情况下均不进行关联操作save-update: 在执行save/update/saveOrUpdate时进行关联操作。delete:      在执行delete时进行关联操作all:         所有情况下均进行关联操作。

12`放弃外键维护inverse

inverse:逆转, 默认值是:flase,不放弃, 设置成:true,放弃外键维护权

  1. 针对1对多的关系:应该由多的这方维护。

13`hibernate:cascade和inverse的区别

  1. 侧重点不同

    • cascade:强调操作一个对象的时候,是否操作其关联对象
    • inverse:强调的是外键的维护权

14`多对多映射文件的编写

hibernate:多对多之建立关系

  1. 数据库:新建表。

  2. java类的表达

  3. hbm.xml映射文件的表达

        <!--    set标签:通过set集合,保存的学生所选的所有课程           name: 类中属性的名字  table: 中间表的名字(表与表关系建立的中间表)         key标签: column: 当前类对应的表,在中间表中的外键字段的名字         many-to-many: class: 找到的课程数据,需要封装的类型。 column: 在中间表中,课程表对应的外键的字段名称    -->    <set name="courses"  table="student_course">        <key column="sc_sid"></key>        <many-to-many  class="cn.itcast.domain.Course"  column="sc_cid" ></many-to-many>    </set>

【记忆的方法】

  • 思考的出发点:查询:已知学生的信息,查询这个学生所选的所有课程
  • 到那里查:中间表,student_course表查询
    • key: 查找的关键,我们现在知道的是学生的信息,我们需要通过学生的学号,在中间表中通过学生表对应的外键,进行查询
    • many-to-many: 标识多对多查询,class查询到的结果,需要封装成那个对象。column:在中间表中,只能获得课程对应的外键,根据这个外籍,查询课程表的记录。

15`hiberante的查询方式:查询方式的概述(面试题)

  • OID查询(get,load)
  • HQL
  • QBC
  • 原生的SQL(SQLQuery查询)
  • 对象导航查询

16`QBC查询

  1. Criteria的使用

    • 通过Session对象,获取Criteria对象。session.createCriteria(Class persistentClass)

    • 通过Restrictions的静态方法创建Criterion对象。每个Criterion对象实例代表一个查询条件

      常见的Restrictions的静态方法
    方法                  说明Restrictions.eq         =Restrictions.allEq      利用Map来进行多个等于的限制Restrictions.gt         >(greater than)Restrictions.ge         >=(greater than or equal)Restrictions.lt         < (less than)Restrictions.le         <=(less than or equal)Restrictions.between    BETWEENlRestrictions.like       LIKERestrictions.in         inRestrictions.and        andRestrictions.or         orRestrictions.sqlRestriction 用SQL限定查询
    • 向Criteria对象添加Criterion查询条件。add()方法
    • 执行list()或者uniqueResult()获得结果。

    • Criteria实际上是一个查询容器,它对查询条件表达式的添加进行了封装。

    • 查询条件Criterion对象,是通过add()方法添加的
    • 查询条件Criterion对象是通过Restrictions的静态方法制定

      1. 高级功能
    • 限定返回的条数(分页查询)

    • setFirstResult()和setMaxResult()结合使用

    • 对查询结果排序

    • Order类,对结果排序,其中asc(升序),desc(降序)

            Criteria criteria=session.createCriteria(Eemployee.class);     criteria.add(Restrictions.ge("id",2));   //>=2        criteria.addOrder(Order.asc("id"));       List list=criteria.list();  
    生成的SQL语句:
        Select * from employee where eid>=2 order by id asc;  
  • 分组和统计

    • hibernate3新增的功能,实现方式:
    • Projection(分组和统计的核心对象), Projections(工具类),ProjectList(添加多个核心对象)

      • Projections.groupProperty(属性名):按照某属性名分组
      • Projections的avg()/rowCount()/count()/max()/min()/countDistinct()等方法来实现统计功能

      实例代码1: 按照部门分组

    Criteria criteria=session.createCriteria(Eemployee.class);Projection projection = Projections.groupProperty("department");criteria.setProjection(projection);

    List list=criteria.list();

    生成的SQL:

       select * from employee group by e_did;  
    实例代码2: 查询编号最大的雇员
      Criteria criteria=session.createCriteria(Eemployee.class);Projection projection = Projections.max("id");criteria.setProjection(projection);  List list=criteria.list();  生成的SQL:      select max(eid) from employee;  

    实例代码3:多条件的分组和统计:查询每个部门的人数

    Criteria criteria = session.createCriteria(Employee.class);
      // 查询条件的集合ProjectionList prolist=Projections.projectionList();prolist.add(Projections.groupProperty("department"));prolist.add(Projections.rowCount());criteria.setProjection(prolist);List<Object[]> list = criteria.list();  生成的SQL:      select e_did, count(*) from employee  group by e_did;  

QBC的皇冠:DetechedCriteria(离线查询对象)(重要)

  1. DetechedCriteria的定义

    • 翻译成离线条件查询,可以脱离Session使用。因为Criteria对象,必须有Session对象创建,即先有Session对象,后有Criteria对象。而DetchedCriteria则无需Session即可创建。
  2. 使用示例

    //1. 创建离线查询对象,并且封装好查询条件 :id =5  -- web层(servlet处理)DetachedCriteria dc = DetachedCriteria.forClass(Employee.class);dc.add(Restrictions.eq("id", 5));//2. 获取session(dao层处理,只需要一个参数:离线查询对象)Session session =HibernateUtils.getCurrentSession();Transaction transaction = session.beginTransaction();//3. 离线查询对象通过session,获得可以使用的CriteriaCriteria  criteria = dc.getExecutableCriteria(session);//4. criteria直接使用,查询条件在离线条件对象时,已经准备好了List<Object[]> list = criteria.list();

修改成:普通Criteria

    Session session =HibernateUtils.getCurrentSession();    Transaction transaction = session.beginTransaction();    Criteria  criteria =Criteria.forClass(Employee.class);    criteria.add(Restrictions.eq("id", 5));    List<Object[]> list = criteria.list();
  1. 意义

提示:从web开发的三层结构分析

  • 实际开发中,查询的条件是不固定 年龄() 爱好()
  • hql查询:非常难受:
    • 什么条件都没有: select a from Employee a where 1=1 ;
    • 用户输入年龄: select a from Employee a where 1=1 and age=? ;

实际开发中,使用QBC(Criteria)查询,离线查询对象。
在web层(servlet里面),创建一个离线查询对象,把所有的查询条件,全部封装到里面。

    DetachedCriteria dc = DetachedCriteria.forClass(Employee.class);     if(age!=null)    {      dc.add(Restrictions.eq("age", ?));    }    if(爱好!=null)    {         dc.add(Restrictions.eq("爱好", ?));    }    dao层代码,传入的参数,只有一个:离线查询对象

17`HQL查询

​ Query

  1. Query的介绍

    • Query代表面向对象的一个hibernate查询。其接受一个HQL语句。
    • HQL:hibernate query language,hibernate查询语言,语法类似SQL,但是是面向对象的。
    • 又成为HQL查询
  2. Query的使用

    • 编写HQL语句。 类似与SQL语句
    • Session对象通过HQL语句,创建Query对象。session.createQuery(String hql)
    • 执行query的list()或者uniqueResult()方法获取结果

18`HQL的多表查询

  1. hibernate的查询中,QBC(Criteria)主要针对单表操作,所以,多表查询,我们只需要关注HQL查询。
  2. 整体分类

    • 连接查询:
    • 交叉连接:from Department, Employee
    • 内连接:
    • 隐式内连接:from Department x, Employee y where x.id = y.department
    • 显式内连接:from Department x inner join x.employees
    • 迫切内连接:from Department x inner join fetch x.employees
      • 都是封装到部门对象,数据重复:select distinct x from Department x inner join fetch x.employees
      • 还可以 new HashSet<>(list) 去list 重复
    • 外连接:
    • 左外连接:from Department x left join x.employees
    • 迫切左外连接: from Department x left join fetch x.employees
    • 右外连接:from Department x right join x.employees

迫切内联接和普通内联接的区别:

  • 普通的内连接:把查询到的结果,封装到两个对象。
  • 迫切内联接:把查询到的结果,封装到一个对象A(前面的那个对象), 另外一个对象B的数据,封装到A对象的关联对象的属性里面。

【总结】

  • 显式内联接:from Department x inner join x.employees(无需写连接条件)
  • 了解迫切内联接与普通内连接的区别
  • 迫切内联接,查询的结果,需要去重。

19`OID查询

hibernate核心API:Session对象中get和load的异同(面试题)

  1. 相同点:

    • 返回值,参数,发送的sql语句,都相同
  2. 不同点:

    • get:立即加载策略:执行get方法,立即发送SQL语句,获得user对象,也是正常的。
    • load:延迟加载策略:懒(lazy)加载:执行load方法,不会立即发送sql语句,只有在真正需要数据的时候,发送SQL语句。获得user对象,本质上一个user的代理对象。
    • 如果找不到对象,get方法:NullPointerException;
    • load方法,报错:ObjectNotFoundException

20`SQL查询

有的应用程序可能需要根据底层数据库的 SQL 方言,来
生成一些特殊的查询语句。在这种情况下,可以利用 Hibernate 提供的 SQL 检索方式。使用 SQL 检
索方式检索对象的示例代码,如下所示:
SQLQuery sqlQuery = session.createSQLQuery(“select id,name,age,city from
customer”);

21`hibernate的查询优化–抓取策略

  • 获取关联对象的时机(开关)。

    1. 抓取策略是什么
  • 简单而言:hibernate如何获取关联对象的方法。

  • 是hibernate提升性能的一种方法。

    • 不过,在使用抓取策略的时候,延迟加载也会影响查询性能,所以,抓取策略和延迟加载,是配合使用。

      1. 为什么学习抓取策略
  • 项目开发中,查询无处不在。但是hibernate本身的查询效率不是很好(hibernate是对jdbc的封装,多一层封装,效率降低一些)。hibernate有关联机制(1对多,多对多),什么时候获取关联对象,如何获取关联对象(控制,什么时候获取),对查询性能的影响很大。所以,hibernate通过抓取策略,来对关联对象的查询,进行优化。

hibernate的延迟加载

  1. 什么是延迟加载

    • 延迟加载的定义
    • 延迟加载,也成为懒加载,只有真正需要数据的时候,才真正执行数据加载操作(sql查询语句)。
    • 延迟加载的分类:
    • 类级别的延迟加载
    • 查询某个对象时,是否延迟,标签上配置lazy属性,默认值是:ture,默认延迟加载。
    • 关联级别的延迟加载。
    • 查询一个对象的关联对象时,是否延迟。在或上配置延迟。
    • hibernate关联对象默认采用延迟加载。可以避免一些无谓的性能开销
  2. 类级别的延迟加载

    • load方法,即类级别的延迟加载。让其失效的方法有两个:
    • 持久化类上,增加final修饰符,让代理对象创建失败。
    • 在上配置lazy=”false”,让延迟加载失效。默认值:true

【实战】

  • 类级别延迟加载,我们一般不修改,采用默认值,因为,如果你想使用立即加载,调用get()方法即可。

关联对象的抓取策略和延迟加载:在set上的fetch和lazy

  • 配置抓取策略,只配置在和上。

场景:查询某个部门,及该部门的员工人数

  1. set标签
    • fetch的取值:抓取策略
      • select.默认值,发送普通的select语句
      • join:发送迫切左外联接去查询, 无所谓lazy的取值
      • subselect。发送一条子查询语句查询其关联对象.(查询多个对象,才能体现)
    • lazy的取值:
      • true。默认值,采用延迟加载
      • false.不采用延迟加载
      • extra. 极其懒惰的

fetch: 抓取策略。确定查询关联对象,使用那种方式(SQL语句)

lazy: 延迟加载。确定什么时候发送SQL语句,查询关联对象

  • 总结:
    • fetch=”join”,发送迫切左外联接,把当前对象及其关联对象,一条语句,全部获取到。无需再次发送SQL语句,进行关联对象查询,也就无所谓延迟加载的设定(lazy失效)
    • fetch=’subselect’,需要查询多个对象,才能体现。lazy是extra的时候,子查询失效。

关联对象的抓取策略和延迟加载:在上的fetch和lazy

注意:1的一方的配置先取消

  1. 标签
    • fetch的取值:
      • select.默认值,发送普通的select语句
      • join:发送迫切左外联接去查询
    • lazy的取值:
      • proxy。默认值,是否延迟取决于一的一方类上lazy属性
      • false.不采用延迟加载
      • no-proxy:不用研究

关联对象的抓取策略:批量抓取

  1. 场景1:查询所有部门,查询每个部门的所有员工的名字

从一的一方开始查询,在set上配置:batch-size=”3”

  1. 场景2:查询所有员工,并且查询其对应部门的名称

从多的一方开始查询,batch-size必须配置在一的一方的标签上

今日内容总结

  1. 核心任务:掌握离线查询对象的使用,以及在项目开发中的作用
  2. 抓取测试,只需要了解即可。
  3. hal多表查询,只需要了解。

hibernate的总结

  1. helloword入门案例
  2. 掌握3种查询的使用:QBC, HQL, SQLQuery查询
  3. 掌握hibernate事务的处理(service层的价值)
  4. SessionFactory工具类,抽取的方法(思路)
  5. 其他,面试的需求,多于工作。(持久类编写规则,三种状态,抓取策略)

hibernaete如何优化(面试题)

a. 使用缓存,hibernate的二级缓存(SessionFactory级别缓存)不适用于集群环境,我们使用redis代替。
b. 配置抓取策略。分析项目需求,对于那些必须使用关联对象的操作,使用立即加载关联对象。

c. 针对不同的项目环境,灵活的处理关联机制()。有一种情况:代码上没有外键,心中有外键。

  • CRM项目:这个软件的使用人数有限(固定),并发特别少
    • 注重数据的安全性,
  • 移动互联网项目:使用的人数特别多,并发量特别大
      • 注重效率。在这种情况下,考虑:放弃外键约束,放弃配置hibernate表与表的关联关系,放弃级联,关联查询这些机制。我在业务的代码中,保证外键的有效性。
原创粉丝点击