Hibernate 框架(一)—— Hibernate 简介、Hibernate 示例、Session 对象

一、Hibernate 简介

1、Hibernate 概述

(1)ORM:对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
(2)Hibernate:Hibernate 是一个开放源代码的对象关系映射框架,它对 JDBC 进行了非常轻量级的对象封装,它将 POJO 与数据库表建立映射关系,是一个全自动的 orm 框架,hibernate 可以自动生成 SQL 语句,自动执行,使得 Java 程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate 可以应用在任何使用 JDBC 的场合,既可以在 Java 的客户端程序使用,也可以在Servlet/JSP 的Web应用中使用。

2、Hibernate 的优点

(1)将对数据库的操作转换为对 Java 对象的操作,从而简化开发。通过修改一个“持久化”对象的属性从而修改数据库表中对应的记录数据。
(2)提供线程和进程两个级别的缓存提升应用程序性能。
(3)有丰富的映射方式将 Java 对象之间的关系转换为数据库表之间的关系。
(4)屏蔽不同数据库实现之间的差异。在 Hibernate 中只需要通过“方言”的形式指定当前使用的数据库,就可以根据底层数据库的实际情况生成适合的 SQL 语句。
(5)非侵入式:Hibernate 不要求持久化类实现任何接口或继承任何类,POJO 即可。

3、Hibernate 核心API

(1)Configuration 类
Configuration 类的作用是对 Hibernate 进行配置,以及对它进行启动。在 Hibernate 的启动过程中,Configuration 类的实例首先定位映射文档的位置,读取这些配置,然后创建一个SessionFactory 对象。

(2)SessionFactory 接口
SessionFactory 接口负责初始化 Hibernate。它充当数据存储源的代理,并负责创建 Session 对象,这里用到了工厂模式。需要注意的是 SessionFactory 并不是轻量级的,因为一般情况下,一个项目通常只需要一个 SessionFactory 就够,当需要操作多个数据库时,可以为每个数据库指定一个 SessionFactory。

(3)Session 接口
Session 接口负责执行被持久化对象的CRUD操作(CRUD的任务是完成与数据库的交流,包含了很多常见的SQL语句)。但需要注意的是 Session 对象是非线程安全的。Hibernate 的session 不同于JSP应用中的 HttpSession。

(4)Transaction 接口
Hibernate 封装的事务接口,通过接口可以管理JDBC事务。

(5)Query 接口
Query 接口让你方便地对数据库及持久对象进行查询,它可以有两种表达方式:HQL语言或本地数据库的SQL语句。Query 经常被用来绑定查询参数、限制查询记录数量,并最终执行查询操作。

(6)Criteria 接口
Criteria 接口与 Query 接口非常类似,允许创建并执行面向对象的标准化查询。值得注意的是 Criteria 接口也是轻量级的,它不能在 Session 之外使用。

二、Hibernate 案例

1、搭建 Hibernate 开发环境步骤

(1)在 Hibernate 官网下载 Hibernate 开发包,下载地址如下:https://sourceforge.net/projects/hibernate/files/hibernate-orm/5.4.2.Final/hibernate-release-5.4.2.Final.zip/download

(2)下载完成之后解压所得到的的目录如下
在这里插入图片描述
documentation:开发文档
lib:Hibernate 提供的 jar 包以及 Hibernate 有可能用到的一些其他第三方的依赖包
project:Hibernate 源码

(3)新建java项目将 lib 文件夹中 required 目录中的所有 jar 包导入到项目中

(4)导入对应的数据库 jdbc 驱动包

(5)在 src 目录下新建 hibernate.cfg.xml,该文件为 hibernate 核心文件,主要用于配置 Hibernate 的相关信息

(6)在 hibernate.cfg.xml 文件中导入 dtd 校验文件,dtd文件主要用于规范和校验 xml 文件中的内容,Hibernate 核心配置文件的 dtd 处于 org.hibernate 包下的 hibernate-configuration-3.0.dtd,复制dtd文件中的 DOCTYPE 部分到 xml 文件中即可。

(7)在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">
<hibernate-configuration>
    <session-factory>
        <!-- 数据库连接配置 -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=utf-8</property>
        <property name="connection.username">root</property>
        <property name="connection.password">admin</property>
        <!-- SQL方言 -->
        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <property name="current_session_context_class">thread</property>
        <!-- 控制台输出SQL语句 -->
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <!-- 在启动时根据配置更新数据 -->
        <property name="hbm2ddl.auto">update</property>
    </session-factory>
</hibernate-configuration>

上述所示配置中的各项 hibernate 属性解释(属性名称一定要写正确且区分大小写):

  • 数据库连接配置
    connection.driver_class:数据库驱动类
    connection.url:数据库连接地址
    connection.username:数据库用户名
    connection.password:数据库密码

  • dialect:方言

  • current_session_context_class:配置 Session 对象的存储容器

  • show_sql:设置为 true 时,将会在控制台打印出执行的 sql 语句,利于调试
    format_sql:设置为 true 时,将会格式化 sql 语句然后在输出

  • hbm2ddl.auto:根据实体类自动创建|更新|验证数据库表结构(正向工程),可选值有:

    1. create:每次加载 Hibernate 时,会先删除原来的表,然后重新创建新表
    2. create-drop:每次加载 Hibernate 时会创建表,SessionFactory 关闭时自动删除表
    3. update:每次加载 Hibernate 时如果表不存在则创建表,如果表存在但是字段信息不正确则会更新字段信息
    4. validate:每次加载 Hibernate 时都会检查实体类和数据库是否一致,如果字段不一致则更新字段,但是不会创建表。
    5. none:不进行正向工程

2、创建实体类和测试类

(1)创建实体类并配置实体类映射信息
在 Hibernate 中配置实体类映射信息有两种方式,配置文件版和注解版,注解版使用更加便捷,推荐使用注解版。
以下以商品信息(Products)类举例:
新建实体类 Products,并在类和属性上添加对应注解,如下

@Entity
@Table 		//可选
public class Products {
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private int p_id;
	@Column		//可选
	private String p_name;
	private double p_price;
	private int p_count;
	private String p_class;
	private String p_attribute;
	private int p_typeid;
	//省略get、set方法
	@Override
	public String toString() {
		return "Products [p_id=" + p_id + ", p_name=" + p_name + ", p_price="
				+ p_price + ", p_count=" + p_count + ", p_class=" + p_class
				+ ", p_attribute=" + p_attribute + ", p_typeid=" + p_typeid
				+ "]";
	}
}

上述使用到的注解解释:

  • @Entity:表示当前类为一个实体类,Hibernate 将会扫描该类上的注解
  • @Table:配置数据库表的信息,通过该注解可以配置实体类映射的表名以及一些其他额外信息
  • @Id:主键映射信息,用来标注当前实体类属性对应的列作为表的主键
  • @GeneratedValue:配置主键生成方式,通过strategy 属性指定,默认情况下,JPA 自动选择一个最适合底层数据库的主键生成策略:SqlServer 对应 identity,MySQL 对应 auto increment。在 javax.persistence.GenerationType 中定义了以下几种可供选择的策略:
    • IDENTITY:采用数据库ID自增长的方式来自增主键字段,Oracle 不支持这种方式;
    • AUTO:JPA自动选择合适的策略,是默认选项;
    • SEQUENCE:通过序列产生主键,通过@SequenceGenerator 注解指定序列名,MySql不支持这种方式
    • TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。
  • @Column:配置实体类属性映射的列名,@Column 注解中属性较多,以下为重要属性详情:
    • name:定义了被标注字段在数据库表中所对应字段的名称
    • unique:表示该字段是否为唯一标识,默认为 false。如果为 true 则会添加唯一约束,如果表中有一个字段需要唯一标识,则既可 以使用该标记
    • nullable:表示该字段是否可以为 null 值,默认为 true,如果为 false 则会添加非空约束。
    • length:表示字段的长度,当字段的类型为 varchar 时,该属性才有效,默认为255个字符。

(2)将所有需要进行对象关系映射的实体类类名在 hibernate.cfg.xml 中告知给 Hibernate,如下:

<mapping class="com.hibernate.entity.Products"/>

(3)新建测试类,获取 Session 连接,并完成查询操作

public class Test {
	public static void main(String[] args) {
		Configuration configure = new Configuration().configure();
		//创建SessionFactory工厂
		SessionFactory sessionFactory = configure.buildSessionFactory();
		//获取Session连接
		Session session = sessionFactory.openSession();
		//查询
		Products products = session.get(Products.class, 3);
		System.out.println(products);
		//关流
		session.close();
	}
}

三、Session 对象

1、Session 对象概述

Session 对象是 Hibernate 中的重要对象,它表示了 Hibernate 与数据库的会话,是对JDBC Connection 的封装,通过该对象我们可以执行增、删、改以及查询单个对象的功能。

2、Session 缓存:一级缓存

(1)在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存。

只要 Session 实例没有结束生命周期, 且没有清理缓存,则存放在它缓存中的对象也不会结束生命周期,位于缓存中的对象称为持久化对象,它和数据库中的相关记录对应。

Session 能够在某些时间点,按照缓存中对象的变化来执行相关的 SQL 语句,来同步更新数据库,这一过程被称为刷新缓存(flush),也叫一级缓存。

(2)以下为 Session 缓存和数据库数据的关系:
在这里插入图片描述

3、Session 的重要方法

(1)flush 方法
session 会按照缓存中对象属性的变化来更新数据库中的记录,使数据库中记录和缓存中的对象保持一致,但是 flush 并不会提交事务。值得注意的是当提交事务时会自动执行 flush 方法更新数据库的记录。

(2)refresh 方法
① 强制发送 select 语句, 以使数据库中的记录和缓存中的对象保持一致。在同一个事务中如果先查询出数据,然后在数据库中手动的修改了数据并且未提交事务之前,然后执行 refresh 的方法会发现同步失败,缓存中的数据并没有被修改,这个问题是事务隔离级别导致的,通过 hibernate 可以修改默认的事务隔离级别。

② 在 Hibernate 中设置事务隔离级别:

  • 0:TRANSACTION_NONE
    不支持事务
  • 1:TRANSACTION_READ_UNCOMMITTED
    可以读取未提交的数据,这种事务隔离级别较低,会造成脏读、幻读、不可重复读的问题
  • 2:TRANSACTION_READ_COMMITTED
    只能读取已提交的事务,这会产生幻读和不可重复读的问题
  • 4:TRANSACTION_REPEATABLE_READ
    可重复读,事务A中先查询一条数据,然后事务B修改了数据并提交,在事务A中重新查询该数据,读取到的数据是修改前的数据不会出现不可重复读的问题
  • 8:TRANSACTION_SERIALIZABLE
    也就是所有事务只能一个个来,不能并发执行

③ 如果没有事务隔离,对于数据库的查询可能会出现以下问题:

  • 脏读:脏读发生在一个事务A读取了被另一个事务B已经修改,但是还未提交的数据。假如B回退,则事务A读取的是无效的数据。
  • 幻读:当事务A查询了一张表的数据总数,事务B对该表数据进行了删除或者新增并提交事务,事务A再次读取数据总数或发现多了一些或者少了一些,这就是幻读。
  • 不可重复读:当事务A读取了一行数据,事务B修改了该行数据并提交了事务,这是事务A再次进行查询发现两次查询的结果不一致,这就是不可重复读的问题。

(3)clear 方法: 清理缓存
由于拥有 Session 缓存机制,Hibernate 将实体类对象分为了三种状态,分别是瞬时、持久、游离。

  • 瞬时状态是指:一个 java 实体类对象在 Session 缓存中不存在并且在数据库中也不存在
  • 持久状态是指:一个 java 实体类对象在 Session 缓存中存在并且在数据库中也存在
  • 游离状态是指:一个 java 实体类对象在 Session 缓存中不存在,但是在数据库中存在

(4)save 方法:新增数据
当实体类id与数据库已有数据主键重复时会抛出异常,save 方法执行成功对象会从瞬时状态变成持久状态。执行新增时,首先考虑主键生成方式:

  • 如果主键是依赖自增列,自增长,序列等等自动生成方式的,那么 Hibernate 在执行 save 时,不会读取实体类id的值。
  • 如果主键不是自增列,自增长,序列等等,那么 Hibernate 在新增时会使用实体类的id属性作为数据行的主键值,这时实体类的id值不能为空且不能和数据库已有的数据重复。

(5)update 方法:更新数据,更新成功对象会从游离状态变成持久状态

  • 若更新一个持久化对象,不必显示的调用 update() 方法,因为在调用 Transaction 的 commit() 方法时,会调用 session 的 flush()
  • 更新一个游离对象,需要显示的调用 update() 方法,可以将一个游离对象转换为持久化对象
  • 当 update() 方法更新一个游离对象时,如果在 Session 的缓存中已经存在相同 OID 的持久化对象,会抛出异常
  • 当 update() 方法关联一个游离对象时,如果在数据库中不存在相应的记录,也会抛出异常。

(6)saveOrUpdate 方法
如果对象是临时对象,则调用 save() 方法,如果对象是游离对象,则调用 update() 方法。
首先考虑主键生成方式:

  • 有主键:实体类对象id值不等于0则执行 update,如果没有给id赋值非0的数据会执行新增,如果id赋值了但是在数据库不存在该id值会去执行更新,但是会抛出异常。
  • 无主键:首先根据id查询当前这行数据,如果数据存在则执行更新,如果数据不存在则执行新增。如果id值为0,也会执行新增。

(7)delete 方法
根据主键删除数据,删除成功对象会从持久状态或者游离状态变为瞬时状态。
在删除和更新时,推荐使用 get 方法或 load 方法将数据查询出来后,再执行 update 和 delete。

(8)get 方法
根据id查询数据,查询不到返回 null,get 方法无延迟加载。

(9)load 方法
根据id查询数据,查询不到抛出异常,load 方法支持延迟加载,即只有当需要使用查询到的这个数据时,才会去执行 load 方法。

发布了75 篇原创文章 · 获赞 10 · 访问量 2906

猜你喜欢

转载自blog.csdn.net/baidu_27414099/article/details/104440121