Hibernate

一、入门及基本介绍

1.1 - Hibernate 概述

1.1.1 - 什么使框架

  • 当我们写程序时,使用框架之后,框架帮我们实现一部分功能
  • 使用框架的好处:少写一部分代码,实现功能

1.1.2 - 什么是 Hibernate

  • 应用于 JavaEE 三层结构中的 DAO
  • 适用于对数据库 CRUD 操作,使用 Hibernate 实现 CRUD 操作,底层代码就是 JDBC
  • 开源的轻量级框架

1.1.3 - 什么是 ORM

  • Object Relational Database-Mapping 对象关系映射
  • 让实体类和数据库进行一一对应
    • 实体类和数据表对应
    • 实体类属性和表的字段
  • 不需要操作表,而是操作表对应的实体类对象

1.2 - 开发环境搭建

  • 新建一个实体类,使其对应数据库中的一条记录。这就要求实体类中的属性与表中的数据一一对应

  • 新建一个配置文件,用于将实体类和数据表对应起来

    • <?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>
      
          <class name="实体类全路径" table="数据表名">
      
              <id name="主属性名" column="主键名">
      
                  <generator class="主键策略"/>
      
              </id>
      
              <property name="属性名" column="字段名" type="数据类型"/>
      
          </class>
      
      </hibernate-mapping>
      
      - 主键策略
          - increment 自动增长
          - identity 自动增长(MySQL)
          - sequence 序列(Oricle)
          - native 根据情况自动选择
          - uuid 随机生成的一个字符串,32 位的 十六进制位
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40

      - 新建 `Hibernate` 的总配置文件,要求在 `src` 文件夹下,名称为 `hibernate.cfg.xml`

      - ```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">

      <hibernate-configuration>

      <session-factory>

      <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
      <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/表名</property>
      <property name="hibernate.connection.username">sql用户名</property>
      <property name="hibernate.connection.password">sql密码</property>

      # 是否显示 SQL 语句
      <property name="hibernate.show_sql">true</property>

      # 是否对 SQL 语句格式规范化
      <property name="hibernate.format_sql">true</property>

      # 设置表的修改方式
      <property name="hibernate.hbm2ddl.auto">update</property>

      # 配置数据库的方言
      <property name="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</property>

      # 配置与本地线程绑定的 Session
      <property name="hibernate.current_session_context_class">thread</property>

      # 引入 实体类-数据表 配置文件
      <mapping resource="com/cying/user.hbm.xml"/>

      </session-factory>

      </hibernate-configuration>
  • 开始使用

    • public class Dao {
          private static Configuration cfg = null;
          private static SessionFactory sif = null;
      
          static {
              cfg = new Configuration().configure();
              sif = cfg.buildSessionFactory();
          }
      
          public static SessionFactory getSessionFactory() {
              return sif;
          }
      
      }
      
      public class Test {
      
          public static void main(String args[]) {
      
              // 获得会话工厂
              SessionFactory sif = Dao.getSeesionFactory();
      
              // 打开会话
              Session session = sif.openSession();
      
              // 开启事务
              Transaction tx = session.beginTransaction();
      
              // 处理逻辑;
      
              // 提交事务
              tx.commit();
      
              // 关闭会话
              session.close;
              sif.close;
      
          }
      
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107

      ## 1.3 - Hibernate 配置文件详解

      ### 1.3.1 - 映射配置文件

      - 映射配置文件名称和位置不固定
      - 映射文件中,标签 `name` 属性值写实体类相关内容
      - `class` 标签 `name` 属性值实体类全路径
      - `id` 标签和 `property` 标签 `name` 属性值,实体类属性名称
      - `id` 标签和 `property` 标签中的 `column` 属性可以省略,值和 `name` 一致
      - `property` 标签 `type` 属性,设置生成表字段的类型,省略时自动对应类型

      ### 1.3.2 - 核心配置文件

      - 三部分要求
      - 数据库部分时必须的
      - `hibernate` 部分可选
      - 映射文件必须的
      - 可信配置文件的文件名和位置固定

      ## 1.4 - Hibernate 的核心 API

      ### 1.4.1 - Configuration

      - 加载配置文件

      ### 1.4.2 - SessionFactory

      * 创建 `SessionFactoy` 过程中做的事:
      * 根据核心配置文件中的数据库配置,及映射文件部分,到数据库里面根据映射关系把表创建

      ### 1.4.3 - Session

      - 相当于 `jdbc` 中的 `Connection`
      - 方法:
      - `save()`
      - `update()`
      - `saveOrUpdate()`
      - `delete()`
      - `get(id)`
      - `load()`
      - `createQuery()`
      - `createCriteria()`
      - `Session` 是单线程对象,不能共用,只能自己使用

      ### 1.4.4 - Transaction

      - 事务
      - 一致性
      - 原子性
      - 隔离性
      - 持久性
      - 方法:
      - `commit()`
      - `rollback()`

      ## 1.5 - Web 内容

      ### 1.5.1 - JavaEE 三层结构

      - **web** 层 -- `Struts2` 框架
      - **Service** 层 -- `Spring` 框架
      - **dao** 层 -- `Hibernate` 框架
      - 对数据库进行增删改查

      ### 1.5.2 - MVC 思想

      - M -- 模型
      - V -- 视图
      - C -- 控制器

      # 二、实体类

      ## 2.1.实体类书写规则

      - 有公开的 `setter` 和 `getter`
      - 要有属性作为唯一的标识
      - 建议使用包装数据类型
      - `Integer`
      - `Character`
      - `String`
      - `Boolean`
      - `Float`
      - `Double`
      - `Long`
      - `Byte`
      - `Short`

      ## 2.2.接口

      ### 2.2.1.save(obj)

      - 调用 `session.save(obj)`

      ### 2.2.2.get(class, id)

      **根据 id 查询**

      - 调用 `session.get(Object.class, id)`

      ### 2.2.3.update(obj)

      - 先查询,然后对返回的对象进行编辑,最后使用 `update()` 来更新

      ```java
      Object obj = session.get( Object.class, id );
      session.update(obj);

2.2.4.delete(obj)

  • 先查询,然后使用 delete() 来删除
1
2
Object obj = session.get( Object.class, id );
session.delete(obj);

2.2.5.saveOrUpdate()

  • 对瞬时态是 save()
  • 对持久态是 update()
  • 对托管态是 update()

2.2.6.Query

  • 不需要写 sql 语句,但是要写 hql 语句
  • hql (Hibernate Query Language)
  • sql 操作的是表和字段
  • hql 操作的是实体类和属性
  • from 实体类名称 – 查询所有
1
2
Query query = session.createQuery("from User");
List<User> list = query.list();

2.2.7.Criteria

1
2
Criteria cta = session.createCreteria(obj.class);
List<obj> list cta.list();

2.2.8.SQLQuery

1
2
3
4
5
6
7
8
// 结果是数据
SQLQuery sql = session.createSQLQuery("SQL语句");
List list = sql.list();

// 结果是对象列表
SQLQuery sql = session.createSQLQuery("SQL语句");
sql.addEntity(obj.class);
List<obj> list = sql.list();

2.3.实体类状态

2.3.1.瞬时态

  • 对象里没有 id 值,对象与 session 没有关联

2.3.2.持久态

  • 对象里面有 id 值,对象与 session 有关联

2.3.3.托管态

  • 对象里面有 id 值,对象与 session 没有关联

三、Hibernate 一级缓存

3.1.什么是缓存

  • 数据存到数据库里面,数据库本身是文件系统,使用流方式操作文件效率不是很高
    • 把数据存到内存里面,不需要使用流方式,可以直接读取内存中的数据
    • 把数据放到内存,提供读取效率

3.2.Hibernate 缓存

  • Hibernate 框架中提供很多优化方式,Hibernate 缓存就是一个优化方式

3.2.1.一级缓存

  • 默认打开
  • 有使用范围(从 session 创建到 session 关闭)
  • 存储数据必须是持久态
  • 有一个快照区

3.2.2.二级缓存

  • 已经不用了
  • 默认不打开
  • 范围是整个 sessionFactory 范围

四、事务的规范写法

1
2
3
4
5
6
7
8
try {
// 开启事务
// 提交事务
} catch() {
// 回滚
} finally {
// 关闭
}

五、绑定 Session

1
2
3
4
sessionFactory.getCurrentSession();

- 需要配置
<property name="hibernate.current_session_context_class">thread</property>

当通过这种方式获取 session 时,线程结束,session 会自动关闭

六、多表操作

6.1.表与表之间关系

6.1.1.一对多

  • 比如:分类和商品的关系,一个分类里面有多个商品,一个商品只能属于一个分类

6.1.2.多对多

  • 比如:订单和商品关系,一个订单里有多个商品,一个商品属于多个订单

6.2.一对多操作

6.2.1.映射配置

创建实体类

在实体类中体现相互的关系·

写配置文件

1
2
3
4
5
6
# 一对多中的多

<set name="属性名" cascade="save-update,delete">
<key column="外键名"/>
<on-to-many class="被引用实体类全路径"/>
</set>
1
2
3
# 一对多中的一

<many-to-one name="set的属性名" class="引用实体类的全路径" cloumn="和上面的外键名一致"/>

6.2.2.级联保存

  • 把一加入多的 Set
  • 把多加入一的属性中
  • 先保存多,再保存一

image-20200215130137452

6.2.3.级联删除

  • 获取多
  • 删除多

image-20200215170516432

6.3.多对多操作

6.3.1.映射配置

  • 多对多需要引入第三张表
1
2
3
4
<set name="Set属性名" table="第三张表名" cascade="save-update">
<key column="在第三张表的外键名"/>
<many-to-many class="另一个表对应的实体类全路径" column="另一张表在第三张表的外键名"/>
</set>

6.3.2.级联保存

  • A 方加入 B 方的 Set,保存 B 方

6.3.3.级联删除

  • 只要从数据库获取某一方,再进行删除即可,但该删除不仅会删除第三张表的对应关系,连同另一张表对应的数据也会被删

七、查询

7.1.对象导航查询

  • 根据 id 查询某个客户,再查询这个客户里面所有联系人

过程

1
2
Object1 obj1 = session.get(Object1.class, id);
Set<Object2> obj2 = obj1.getobj2();

7.2.OID 查询

  • 根据 id 查询某一条记录,返回对象

过程

1
Object obj = session.get(Object.class, id);

7.3.HQL 查询

  • Query 对象,写 HQL 语句实现查询
  • Hibernate Query Language 提供一种查询语言,和普通 SQL 有区别

7.3.1.查询所有

1
2
3
4
Query query = session.createQuery("from 实体类");
List<Object> list = query.list();

for(Object obj : list) {}

7.3.2.条件查询

1
2
3
4
5
6
7
Query query = session.createQuery(from 实体类 where 实体类属性 = ? and ...);
query.setParameter(index, value);
List<Object> list = query.list();

for(Object obj : list) {}

// index 从 0 开始
1
2
3
4
5
6
7
8
Query query = session.createQuery(from 实体类 where 实体类属性 like ? and ...);
query.setParameter(index, value);
List<Object> list = query.list();

for(Object obj : list) {}

// %
// index 从 0 开始

7.3.3.排序查询

1
2
3
4
5
6
Query query = session.createQuery(from 实体类 order by 实体类属性 asc/desc);
List<Object> list = query.list();

for(Object obj : list) {}

// index 从 0 开始

7.3.4.分页查询

1
2
3
4
5
6
7
8
Query query = session.createQuery(from 实体类);
query.setFirstResult(start);
query.setMaxResult(max);
List<Object> list = query.list();

for(Object obj : list) {}

// index 从 0 开始

7.3.5.投影查询

1
2
3
4
5
6
7
Query query = session.createQuery(select 属性名1... from 实体类);
query.setParameter(index, value);
List<Object> list = query.list();

for(Object obj : list) {}

// index 从 0 开始

7.3.6.聚集函数使用

1
2
3
4
Query query = session.createQuery(select 函数() from 实体类);
Object obj = query.uniqueResult();

// int 需要先强转 Long,然后用 Long 的对象.intValue() 获取