Loading

Hibernate 学习笔记

hibernate(持久化)

一. Hibernate 的理解

Hibernate 是数据访问层(Dao层),就是把数据存入到数据库中,称为持久化。

Hibernate 对 JDBC 进行了封装,针对数据访问层提出面向对象的思想,操作对象间接的操作数据库中的表,自动生成 SQL 语句,可以简化数据访问层的代码,提高开发效率。

二. hibernate的优缺点

  • 优点:

    • 使用 JDBC 遇到的问题:

      1. 代码中存在大量的 SQL 语句

      2. 查询结果需要手动封装到 Model

      3. SQL 语句中存储大量的?,需要手动赋值

      4. SQL 语句根据不同的数据库,有不同的函数,如果更换数据库,需要大量更改 SQL 语句,针对数据库移植性差

    • 使用 Hibernate 可以解决以上问题:

      1. Hibernate 操作对象自动生成 SQL 语句

      2. 查询结果自动赋值给 Model 类

      3. 自动赋值

      4. Hibernate 使用的是 HQL 语句,根据不同的方言,生成不同数据库的 SQL 语句,到达跨数据库平台

        注:数据迁移是软性项目中的大事情,特别难做,做项目时对数据库的选型尤为重要

  • 缺点:

    1. SQL语句自动生成,人工无法控制,使得 SQL 语句执行效率慢
    2. Hibernate 执行效率低
    3. Hibernate 特别耗内存,有一系列缓存机制

三. 什么是ORM(☆)

ORM 是一种编程思想(开发模式),全称:Object Relation Mapper(对象关系映射)

是为了解决面向对象与面向关系型数据库不匹配现象,通过一个配置文件把面向对象与面向关系型数据库关联起来

  • 类 --- 表
  • 属性 --- 字段
  • 对象 --- 记录
优点:使得数据访问层更面向对象,不用考虑关系型数据库,只要会面向对象即可,开发程序变简单了(Hibernate、MyBatis、Spring、JDBC)

四、搭建 Hibernate 环境

  1. 导包:在hibernate-release-4.3.11.Final/lib/required下所有 Jar 文件与数据库驱动包复制到项目中
  2. 引入 Hibernate 主配置文件,Hibernate.cfg.xml文件复制到项目中的 src 目录
  3. 创建一个 Model 类实现 Serializable 接口,对应一个表,并且在映射文件xxx.hbm.xml中配置
  4. 编写 Hibernate API 进行测试

五. Hibernate 的体系结构(Hibernate由哪几部分组成)(☆)

结构 描述
hibernate.cfg.xml 是 Hibernate 的主配置文件,用来配置数据库连接信息与 Hibernate 相关参数
XXX.hbm.xml 类与表之间的映射文件,一个类对应一个表,一个属性对应一个字段
实体类 用于封装数据库的表,一定要实现 Serializable 接口
Hibernate API 用于读取并解析配置文件,然后根据映射关系生成 SQL 语句,间接操作数据库

六. Hibernate 工作原理(☆)

  1. Configuration 类读取并解析配置文件(主配置文件、映射文件)
  2. 创建 SessionFactory(一个 SessionFactory 对应一个数据库)
  3. 打开 Session(Session 代表程序与数据库之间的一次会话,用来做表的增删改查)
  4. 创建事务(Transaction 代表数据库事务)
  5. 持久化操作(增删改查)
  6. 提交事务
  7. 关闭 Session
  8. 当应用程序停止,关闭 SessionFactory

注:SessionFactory 是一个重量级对象,创建销毁特别耗资源,应用程序创建一次,关闭一次

七. Hibernate 代码工作原理

  1. 获取 Configuration 类的对象(cfg)

  2. 调用 cfg.configure() 方法默认读取 src 根目录下的 hibernate.cfg.xml

  3. 调用cfg.buildSessionFactory()方法创建 Session 工厂(sf)

  4. 调用sf.openSession()方法获取 Session

  5. 若为添加、删除、修改操作,则开启事务

    Transaction ts = session.getTransaction()
    ts.begin();
    
  6. 进行持久化操作

    添加:e(obj);			
    删除:delete(obj);			
    修改:update(obj);			
    查询:get(类名.class, 1);	
    查询:load(类名.class, 1);
    添加和修改都支持:saveOrUpdate(obj);	
    
  7. 提交事务,关闭 Session,关闭 SessionFactory

    ts.commit();
    session.close();
    sf.close();
    

八. Hibernate 的映射类型

Hibernate 映射文件xxx.hbm.xml中,Java 数据类型与数据库数据类型相互转换,通过 type 属性进行指定,类型如下:
  1. 整数

    Java 类型 type 取值
    byte byte
    short short
    int Integer
    long long
  2. 小数

    Java 类型 type 取值
    float float
    double double
  3. 字符串

    Java 类型 type 取值
    String String
  4. 日期

    Java 类型 type 取值
    java.util.Date date
    java.sql.Date date
  5. 时间

    Java 类型 type 取值
    java.sql.Timestamp timestamp

注:建议手动创建表,不要让 Hibernate 生成表格,hibernate.hbm2ddl.auto配置成为 update

九. Hibernate 核心开发接口(常用的类与接口)(☆)

接口 描述
Configuration 读取并解析配置文件,然后创建 SessionFactory(是一个类)
SessionFactory 代表一个数据库,一个 SessionFactory 对应一个数据库,用于创建 Session(是一个接口)
Session 程序与数据库的一次会话,用于数据库表的增删改查(是一个接口)
Transaction 事务管理(是一个接口)
Query 与 Criteria 用于数据查询(是一个接口)

十. Hibernate 有多少种查询

  1. 主键查询:get()load()
  2. HQL 查询
  3. SQL 查询
  4. QBC 查询

查询效率由高到低排列:主键查询 > SQL 查询 > HQL 查询 > QBC 查询

十一. 查询方法延迟加载(☆)

  1. 什么是延迟加载?

    Hibernate 中存在一些方法,在查询的时候并没有马上发送 SQL 语句去数据库查询,而是返回一个空值对象,空值对象不是 null,而是新 new 出来的对象,除主键以外其他属性值为空,当程序真正使用到此对象时,才会发送 SQL 语句去数据库中查询,并且将结果赋值给此对象,这种查询称为延迟加载

  2. 为什么要用延迟加载?

    1. 在延迟的这段时间内,并没有访问数据库,可以节约内存开销,减少数据库的访问,提高使用效率
    2. 可以防止查询对象,但并没有真正的使用,这种情况下可以节约内存,减少数据库访问
  3. 如何使用延迟加载?

    1. Hibernate 中一些方法自带延迟加载机制,只要调用这些方法,就可以使用延迟加载

    2. 具有延迟加载机制的访问如下

      延迟加载 立即加载
      session.load() session.get()
      query.iterate() query.list()
  4. get() 与 load() 区别(☆)

    get():立即加载,立即发送 SQL 语句查询,如果没有查询到结果返回 null

    load():延迟加载,不会立即发送 SQL 语句查询,返回一个空值对象,真正使用到此对象,才会发送 SQL 语句。如果没有查询到结果,会抛出ObjectNotFoundException异常

  5. list() 与 iterate() 区别

    list():立即加载,立即发送 SQL 语句查询,返回一个对象集合,如果没有查询到数据,返回空集合

    iterate():延迟加载,首先会发送一条 SQL 语句把表中所有主键查询出来,在遍历的时候,根据主键发送 SQL 语句单个查询,有多少条记录就会发送多少条 SQL 语句查询

    注:建议使用立即加载

十二. 一级缓存(☆)

  1. 什么是一级缓存?

    Hibernate 在创建 Session 的时候,会给每个 Session 另外分配一片内存空间,用于缓存 Session 操作过的对象,这块儿内存称为一级缓存,一级缓存是

    Session 管理并且使用的,所以也称为:Session 缓存。

    一级缓存的生命周期与 Session 一致,Session 被创建时,一级缓存空间被分配,session.close()时,一级缓存被回收

  2. 一级缓存的作用?

    一级缓存用来缓存 Session 操作过的对象,相同数据不用每次都去查询数据库,直接从一级缓存中获取,提高查询效率

  3. 一级缓存的步骤?

    Session 优先查询一级缓存,首先去一级缓存中查询,查询不到才会发送 SQL 语句查询数据库,查询到结果之后会在一级缓存中存放一份,再次查询时,无需发送 SQL 语句查询数据库,直接从一级缓存中获取(在 Hibernate 中一级缓存优先于数据库,一级缓存与数据库数据不同步时,以一级缓存为主)

  4. 如何使用一级缓存?

    1. 一级缓存是默认开启,自动使用

    2. 一级缓存的特征:

      • 一级缓存是 Session 独享的,Session 与 Session 之间不能共享数据
      • Session 查询一组数据时,会将一组数据拆开存入一级缓存中,一级缓存中存储的是单个对象
      • 执行增删改时会同步一级缓存,当delete(Object obj)时,在一级缓存中会标记此对象可能被删除,再次查询时不会发送 SQL 语句查询,返回一个null 对象
    3. 管理缓存

      • clear():清空一级缓存
      • evict():清空一级缓存单个对象
      • flush():手动同步一级缓存与数据库,数据不一样,以一级缓存为主

十三. 二级缓存

SessionFactory 级别的缓存(需要配置)

Hibernate 二级缓存需要配置,在同一 SessionFactory 范围内,查询同一个对象多次,只会发送一条 SQL 语句(只会去数据库中查询一次),后面每次查询都是从二级缓存中去取数据

配置信息:
  1. 导入二级缓存的 Jar 包 ehcache oscache
  2. 把对应配置文件放入到 src 根目录下
  3. Hibernate.cfg.xml中开启二级缓存
  4. 声明哪些对象需要放入到二级缓存中

十四. 对象的持久性

什么是对象的持久性?

​ Hibernate 操作对象时,可以把对象看成三种状态::瞬时态,持久台,游离态/托管态

三种状态的规则?
  1. 瞬时态(transient)

    • 定义:对象刚刚被 new 出来,称为瞬时态
    • 规则:瞬时态可以被垃圾回收机制回收,一级缓存中没有,数据库中没有
  2. 持久态(persistent)

    • 定义:一级缓存中有,数据库中有,称为持久态
    • 规则:通过 save(),update(),saveOrUpdate(),get(),load(),HQL,SQL,QBC 方式操作过的对象,称为持久态对象
  3. 游离态(detached)

    • 定义:一级缓存中没有,数据库中有,称为游离态
    • 规则:通过 clear,evict,close 方式操作过的对象, 称为游离态对象

十五. 主键的生成策略

在映射文件(xxx.hbm.xml)中需要配置主键字段,并且需要配置主键的生成策略,通过 generator 标签指定
主键生成策略:
  1. sequence

    代码如下:

    <generator class="sequence">
    	<!-- 指定序列的名称 -->
    	<param name="sequence">t_person_seq</param>
    </generator>
    

    对应数据库:Oracle,DB2

  2. identity

    代码如下:

    <generator class="identity"></generator>

    对应数据库:MySQL,SQL Server

  3. native

    代码如下:
    <generator class="native"></generator>

    含义:native 是让 hibernate 自动选择一种主键方式,根据配置文件中的方言,从 sequence 与 identity 中选一个,方言配置的是 Oracle ,自动选择sequence,方言配置的是MySQL,自动选择 identity

  4. assigned

    代码如下:

    <generator class="assigned"></generator>

    含义:程序员手动分配主键,Hibernate 不会自动生成

  5. uuid

    代码如下:

    <generator class="uuid"></generator>

    含义:采用 UUID 算法生成一个32位十六进制的字符串作为主键

  6. increment

    代码如下:

    <generator class="increment"></generator>

    含义:查询表中最大 id 值, 把最大 id + 1 生成主键

    优点:适用与任何数据库

    缺点:并发量大时,会产生相同的 id,线程不安全,不推荐使用

十六. 关系映射

什么是关系映射?

​ 如果两张表之间有关系,Hibernate 允许我们将关系提取出来,并且映射的配置文件中,在对一个表的增删改查操作,Hibernate 通过这个映射关系,间接的操作另一张表的增删改查,这两个表的关系配置称为关系映射

关系映射类型?
  1. 多对一
  2. 一对多
  3. 一对一
  4. 多对多

十七. 多对一(重点)与一对多

  1. 设计

    两张表之间的关系为多对一或一对多,会在多的一端增加一个字段指向一的那端的主键

  2. 案例

    学生与班级:多个学生属于一个班级,一个班级有多个学生

    一对多添加会产生 N+1 条,尽量少用一对多,用多对一代替

    一对多配置:
    <!--
    set标签:指定是 set 集合
    name属性:类中的属性名
    -->
    <set name="students">
    
    <!--
    key标签:指定两个表之间关联字段(外键字段名称)
    column属性:外键字段的字段名
    -->
    <key column="f_classId"></key>
    
    <!--
    one-to-many标签:表示与哪个类发生了一对多的关系
    class属性:多对那端类的名称
    -->
    <one-to-many class="Student" />
    </set>
    
    多对一配置:
    <!--
    many-to-one 标签:多对一关系
    name 属性:类中属性的名称
    column 属性:表中的字段名(外键字段名)
    class 属性:外键属性的类(完整路径)
    -->
    <many-to-one name="cla" column="f_classId" class="com.zt.model.Classes"></many-to-one>
    

十八. 关联操作

关联查询(查询)
  • 延迟加载(对于关联属性,Hibernate 默认采用的是延迟加载,查询一端数据,不会关联出另一端数据)

    lazy="proxy/true" 	默认方式,采用懒加载
    lazy="false"		立即加载,关联的表数据会同时查询出来
    
  • 连接查询

    fetch="select"	默认方式,使用多条 SQL 语句查询
    fetch="join"	使用连接查询,一条 SQL 语句完成查询,使用此属性懒加载失效
    
  • join 查询

    String hql = "from Student s left join fetch s.cla";  左外连接
    String hql = "from Student s inner join fetch s.cla";  内连接
    
级联操作(增删改)
  • 什么是级联操作?

    在对一张表做增删改操作时,关联的另一张表也做增删改操作,称为级联操作

  • 如何设置级联操作?

    在映射文件中,关联映射配置 cascade 属性,用这个属性定义级联操作

  • cascade取值如下:

取值方式 描述
none 默认方式,不支持级联
all 支持增删改
save-update 支持增,改
delete 支持删

十九. 一对一(了解)

一对一的类型:

​ 主键一对一:包装两个标段主键相同

​ 外键一对一:在任意一端增加一个字段(外键字段)指向另一端的主键,并且这个字段有唯一约束(不能重复)

案例:

​ 学生与档案一对一,在学生表中增加一个字段指向档案表的主键,外键保证唯一性

二十. 多对多

什么是多对多?

​ 如果两张表的关系是多对多,必然产生一张中间表,中间表只有两个字段,分别为两张表的外键字段,这两个外键字段组合成复合主键

案例:

​ 一个班级由多个老师教学,一个老师可以教多个班级

多对多配置:
<!-- 
set标签:指定是 set 集合
name属性:类中的属性名
table:中间表的表名
-->
<set name="teachers" table="t_cla_tea">

<!--
column属性:当前表的主键的对应中间表的外键字段
-->
<key column="f_classId"></key>

<!--
many-to-many标签:多对多的关系映射
class属性:当前 set 集合元素对应的类名
column属性:对方表的主键对应中间表的外键字段名
-->
<many-to-many class="Teacher" column="f_teacherId"/>
</set>

二十一. Hibernate 查询语句

  1. 主键查询:load,get
  2. HQL 查询(Hibernate Query Language) :标准的SQL + 面向对象语言
  3. QBC 查询(Query By Criteria):完全的面向对象
  4. SQL 查询(Structured Query Language):结构化查询语言
posted @ 2022-03-22 21:30  Schieber  阅读(243)  评论(0编辑  收藏  举报