Hibernate


1.ORM是什么

ORM 是 Object Relational Mapping 的缩写,译为“对象关系映射”,它解决了对象和关系型数据库之间的数据交互问题。

ORM 是一种自动生成 SQL 语句的技术,它实现了对象和关系型数据库之间的数据交互,提高了开发效率。在实际开发中,常见的增删改查(CRUD)操作都可以交给 ORM,避免了手写 SQL 语句的麻烦。

总结:是什么?实现对象关系映射,自动生成sql语句。


2.Hibernate是什么

Hibernate 是一个用来连接和操作数据库的 Java 框架,它最大的优点是使用了 ORM 技术。

一种全自动的 ORM 框架

对应关系是双向的:

  • 将数据表对应到 Java 对象上,这样数据表中的数据就能自动提取到 Java 对象中;

  • 将 Java 对象对应到数据表上,这样 Java 对象中的数据就能自动存储到数据表中。

MyBatis 虽然是一种 ORM 框架,但它建立的映射关系是不完整的。Mybatis 只能将数据表映射到 Java 对象上,却不能将 Java 对象映射到数据表上,所以数据只能从数据表自动提取到 Java 对象中,反之则不行。要想将 Java 对象中的数据存储数据表中,开发人员需要手动编写 SQL 语句,依然非常麻烦,这就是 MyBatis 被称为半自动 ORM 框架的原因。

提供了缓存机制

提供了缓存机制(一级缓存、二级缓存、查询缓存),我们可以将那些经常使用的数据存放到 Hibernate 缓存中。当 Hibernate 在查询数据时,会优先到缓存中查找,如果找到则直接使用,只有在缓存中找不到指定的数据时,Hibernate 才会到数据库中检索,因此 Hibernate 的缓存机制能够有效地降低应用程序对数据库访问的频次,提高应用程序的运行性能。

JDBC vs Hibernate

 JDBCHibernate 
代码量 代码繁琐,开发成本较高。 代码精简,开发成本较低。
语言 JDBC 使用的是基于关系型数据库的标准 SQL 语句。 Hibernate 使用的是 HQL(Hibernate query language)语句。
操作的对象 JDBC 操作的是数据,将数据通过 SQL 语句直接传送到数据库中执行。 Hibernate 操作的是 Java 对象。Hibernate 使用了 ORM 思想,在 Java 对象与数据库表之间建立映射关系,通过操作 Java 对象来实现对数据库的操作。
缓存 JDBC 没有提供缓存机制。 Hibernate 提供了缓存机制(例如一级缓存、二级缓存、查询缓存),对于那些经常使用的数据,可以将它们放到缓存中,不必在每次使用时都去数据库查询,缓存机制对提升性能大有裨益。
可移植性 JDBC 可移植性差,JDBC 中使用的 SQL 语句是以字符串的形式嵌入到代码中的,但不同数据库所使用的的 SQL 语法不尽相同,如果切换数据库(例如从 MySQL 数据库切换到 Oracle 数据库),需要修改大量代码。 Hibernate 可移植性好,能够屏蔽不同数据库之间的差异。当需要更换数据库时,通常只需要修改其配置文件(hibernate.cfg.xml)中的 hibernate.dialect(方言) 属性,指定数据库类型即可,Hibernate 会根据指定的方言自动生成适合的 SQL 语句。
读写性能 JDBC 是 Java 领域内性能最好的数据库访问技术。 Hibernate 性能较差。
可扩展性 JDBC 不具有可扩展性 Hibernate 框架开源免费,用户可以根据自身需要进行功能定制,具有良好的可扩展性。

 

总结:什么是Hibernate?

  1. 一种全自动化的ORM框架,支持双向关系映射,不需要手写sql。

  2. 提供缓存机制,不用每次都进行查表操作,性能好。

  3. 支持多种数据库,可移植性好,切换数据库时,修改对应的配置文件即可,不需要因为不同数据库的SQL语法不同,修改大量的sql代码。


3.Hibernate项目创建流程(IDEA版)

demo示例

pom文件导入依赖:

<?xml version="1.0" encoding="UTF-8"?>

         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    4.0.0

    com.example
    hibernatedemo
    1.0-SNAPSHOT

    
        
        
            org.hibernate
            hibernate-core
            5.6.5.Final
        
        
        
            mysql
            mysql-connector-java
            5.1.47
        
        
            junit
            junit
            4.12
            test
        
    

    
    
        
            
                src/main/java
                
                    **/*.properties
                    **/*.xml
                
                false
            
            
                src/main/resources
                
                    **/*.properties
                    **/*.xml
                
                false
            
        
    

数据库表建立:

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `user_id` varchar(255) DEFAULT NULL,
  `user_name` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

INSERT INTO `user` VALUES ('1', '001', 'admin', 'admin', '12345678@qq.com');
INSERT INTO `user` VALUES ('2', '002', 'user', '123456', '98765432@qq.com');

实体类建立:

package com.example.hibernatedemo.po;

/**
 * @DESC
 * @AUTHOR lh
 * @DATE 2022/2/17 10:54
 */
public class User {

    private int id;
    private String userId;
    private String userName;
    private String password;
    private String email;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "net.biancheng.www.po.User{" +
                "id=" + id +
                ", userId='" + userId + '\'' +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}

数据库表与实体类建立关系映射:

User.hbm.xml

<?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="com.example.hibernatedemo.po.User" table="user" schema="hibernatedemo">
        
        <id name="id" column="id">
            
            <generator class="native">generator>
        id>
        
        
        
        
        
        <property name="userId" column="user_id" type="java.lang.String"/>
        <property name="userName" column="user_name"/>
        <property name="password" column="password"/>
        <property name="email" column="email"/>
    class>
hibernate-mapping>

数据库连接配置文件

hibernate.cfg.xml:

<?xml version='1.0' encoding='utf-8'?>
DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

    <session-factory>
        
        <property name="connection.url">jdbc:mysql://127.0.0.1:3306/hibernatedemoproperty>
        <property name="hibernate.connection.username">rootproperty>
        <property name="hibernate.connection.password">123456property>
        <property name="connection.driver_class">com.mysql.jdbc.Driverproperty>
        
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialectproperty>
        
        <property name="hibernate.show_sql">trueproperty>
        
        <property name="hibernate.format_sql">trueproperty>
        
        <mapping resource="com/example/hibernatedemo/mapping/User.hbm.xml"/>
    session-factory>
hibernate-configuration>

测试类编写:

import com.example.hibernatedemo.po.User;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

/**
 * @DESC
 * @AUTHOR lh
 * @DATE 2022/2/17 10:59
 */
public class MyTest {
    /**
     * 查询数据库数据
     */
    @Test
    public void testQuery() {
        //Hibernate 加载核心配置文件(有数据库连接信息)
        Configuration configuration = new Configuration().configure();
        //创建一个 SessionFactory 用来获取 Session 连接对象
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        //获取session 连接对象
        Session session = sessionFactory.openSession();
        //开始事务
        Transaction transaction = session.beginTransaction();
        //根据主键查询 user 表中的记录
        User user = session.get(User.class, 1);
        System.out.println(user);
        //提交事务
        transaction.commit();
        //释放资源
        session.close();
        sessionFactory.close();
    }
}

运行结果:

Hibernate: 
    select
        user0_.id as id1_0_0_,
        user0_.user_id as user_id2_0_0_,
        user0_.user_name as user_nam3_0_0_,
        user0_.password as password4_0_0_,
        user0_.email as email5_0_0_ 
    from
        user user0_ 
    where
        user0_.id=?
net.biancheng.www.po.User{id=1, userId='001', userName='admin', password='admin', email='12345678@qq.com'}

4.Hibernate增删改查操作(CRUD)

插入记录

Hibernate 在 Session 接口中为我们提供了一个 save() 方法,该方法可以向据库表中插入记录

@Test
    public void testInsert() {
        // 加载Hibernate核心配置文件
        Configuration configuration = new Configuration().configure();
        // 创建一个SessionFactory用来获取Session对象
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        // 获取session连接对象
        Session session = sessionFactory.openSession();
        // 开始事务
        Transaction transaction = session.beginTransaction();
        // 创建实体类对象
        User user = new User();
        user.setUserId("003");
        user.setUserName("李嘉图");
        user.setPassword("123456");
        user.setEmail("12345678@qq.com");
        // 向user表中插入数据,返回值为新增数据的主键id
        Serializable save = session.save(user);
        System.out.println("新增的数据主键 id:" + save);
        // 提交事物
        transaction.commit();
        // 释放资源
        session.close();
        sessionFactory.close();
    }
Hibernate: 
    insert 
    into
        user
        (user_id, user_name, password, email) 
    values
        (?, ?, ?, ?)
新增的数据主键 id:4

修改记录

Hibernate 在 Session 接口中为我们提供了一个 update() 方法,该方法可以用来修改数据库表中的记录。

update() 方法会更新指定记录的全部字段,对于我们没有指定的字段,Hibernate 则将其修改为默认值

采用“先查询再修改”的方式进行更新。

@Test
    public void testUpdate() {
        //加载 Hibernate 核心配置文件
        Configuration configuration = new Configuration().configure();
        //创建一个 SessionFactory 用来获取 Session 连接对象
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        //获取session 连接对象
        Session session = sessionFactory.openSession();
        //开始事务
        Transaction transaction = session.beginTransaction();
        //现将需要修改的记录查询出来
        User user = session.get(User.class, 3);
        //设置需要修改的字段
        user.setUserName("meiguoduizhang");
        //直接调用 update() 方法进行修改
        session.update(user);
        //提交事务
        transaction.commit();
        //释放资源
        session.close();
        sessionFactory.close();
    }

删除记录

Hibernate 在 Session 接口中,为我们提供了一个 delete() 方法,该方法用于删除数据库表中的记录。

@Test
    public void testDelete() {
        //加载 Hibernate 核心配置文件
        Configuration configuration = new Configuration().configure();
        //创建一个 SessionFactory 用来获取 Session 连接对象
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        //获取session 连接对象
        Session session = sessionFactory.openSession();
        //开始事务
        Transaction transaction = session.beginTransaction();
        User user = new User();
        user.setId(3);
        //删除指定的记录
        session.delete(user);
        //提交事务
        transaction.commit();
        //释放资源
        session.close();
        sessionFactory.close();
    }

查询数据

查询单条数据:

Hibernate 通过 Session 接口提供的 get() 方法能够查询出一条指定的数据。

查询多条数据:

三种查询方式

  • HQL 查询

  • QBC 查询

  • SQL 查询

HQL 查询

HQL 全称:Hibernate Query Language,它是一种面向对象的查询语言,它和 SQL 的语法相似,但 HQL 操作的是实体类对象及其中的属性,而不是数据库表中的字段。在 Hibernate 提供的各种检索方式中,HQL 是使用最广的一种检索方式。

@Test
    public void testHqlQuery() {
        //加载 Hibernate 核心配置文件
        Configuration configuration = new Configuration().configure();
        //创建一个 SessionFactory 用来获取 Session 连接对象
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        //获取session 连接对象
        Session session = sessionFactory.openSession();
        //开始事务
        Transaction transaction = session.beginTransaction();

        //创建 HQL 语句,语法与 SQL 类似,但操作的是实体类及其属性
        Query query = session.createQuery("from User where email like ?1");
        //查询所有使用 163 邮箱的用户
        query.setParameter(1, "%@163.com%");
        //获取结果集
        List resultList = query.getResultList();
        //遍历结果集
        for (User user : resultList) {
            System.out.println(user);
        }

        //提交事务
        transaction.commit();
        //释放资源
        session.close();
        sessionFactory.close();
    }
Hibernate: 
    select
        user0_.id as id1_0_,
        user0_.user_id as user_id2_0_,
        user0_.user_name as user_nam3_0_,
        user0_.password as password4_0_,
        user0_.email as email5_0_ 
    from
        user user0_ 
    where
        user0_.email like ?
net.biancheng.www.po.User{id=5, userId='003', userName='user2', password='user2', email='9dfasdfa@163.com'}
net.biancheng.www.po.User{id=6, userId='004', userName='user3', password='user3', email='76543345@163.com'}
net.biancheng.www.po.User{id=7, userId='005', userName='user4', password='user4', email='234543546@163.com'}

5.Hibernate工作原理

Hibernate 工作流程一般分为如下 7 步

  1. Hibernate 启动,Configruation 会读取并加载 Hibernate 核心配置文件和映射文件钟的信息到它实例对象中。

  2. 通过 Configuration 对象读取到的配置文件信息,创建一个 SessionFactory 对象,该对象中保存了当前数据库的配置信息、映射关系等信息。

  3. 通过 SessionFactory 对象创建一个 Session 实例,建立数据库连接。Session 主要负责执行持久化对象的增、删、改、查操作,创建一个 Session 就相当于创建一个新的数据库连接。

  4. 通过 Session 对象创建 Transaction(事务)实例对象,并开启事务。Transaction 用于事务管理,一个 Transaction 对象对应的事务可以包含多个操作。需要注意的是,Hibernate 的事务默认是关闭的,需要手动开启和关闭。

  5. Session 接口提供了各种方法,可以对实体类对象进行持久化操作(即对数据库进行操作),例如 get()、load()、save()、update()、saveOrUpdate() 等等,除此之外,Session 对象还可以创建Query 对象 或 NativeQuery 对象,分别使用 HQL 语句或原生 SQL 语句对数据库进行操作

  6. 对实体对象持久化操作完成后,必须提交事务,若程序运行过程中遇到异常,则回滚事务。

  7. 关闭 Session 与 SessionFactory,断开与数据库的连接,释放资源


 

6.hibernate.cfg.xml(Hibernate核心配置文件)

<?xml version='1.0' encoding='utf-8'?>
DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

    <session-factory>
        
        <property name="connection.url">jdbc:mysql://127.0.0.1:3306/hibernatedemoproperty>
        <property name="hibernate.connection.username">rootproperty>
        <property name="hibernate.connection.password">123456property>
        <property name="connection.driver_class">com.mysql.jdbc.Driverproperty>
        
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialectproperty>
        
        <property name="hibernate.show_sql">trueproperty>
        
        <property name="hibernate.format_sql">trueproperty>
        
        <mapping resource="com/example/hibernatedemo/mapping/User.hbm.xml"/>
    session-factory>
hibernate-configuration>
property 属性名描述是否为必需属性
connection.url 指定连接数据库 URL
hibernate.connection.username 指定数据库用户名
hibernate.connection.password 指定数据库密码
connection.driver_class 指定数据库驱动程序
hibernate.dialect 指定数据库使用的 SQL 方言,用于确定 Hibernate 自动生成的 SQL 语句的类型
hibernate.show_sql 用于设置是否在控制台输出 SQL 语句
hibernate.format_sql 用于设置是否格式化控制台输出的 SQL 语句
hibernate.hbm2ddl.auto 当创建 SessionFactory 时,是否根据映射文件自动验证表结构或自动创建、自动更新数据库表结构。 该参数的取值为 validate 、update、create 和 create-drop
hibernate.connection.autocommit 事务是否自动提交

7.Hibernate映射文件(Xxx.hbm.xml)

<?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 schema="hibernatedemo">

    
    
    
    <class name="com.example.hibernatedemo.po.User" table="user">
        
        <id name="id" column="id">
            
            <generator class="native">generator>
        id>
        
        
        
        
        
        <property name="userId" column="user_id" type="java.lang.String"/>
        <property name="userName" column="user_name"/>
        <property name="password" column="password"/>
        <property name="email" column="email"/>
    class>
hibernate-mapping>

1.设置连接的数据库。

2.实体类与数据库表建立映射关系。

3.配置主键生成策略。


 

 

8.Hibernate核心接口(5个)

 

在 Hibernate 中有 5 个常用的核心接口,它们分别是 Configuration 接口、SessionFactory 接口、Session 接口、Transaction 接口和 Query 接口。

 

1. Configuration

 

正如其名,Configuration 主要用于管理 Hibernate 配置信息,并在启动 Hibernate 应用时,创建 SessionFactory 实例。

 

自己找到后加载:

Configuration configuration = new Configuration().configure();

指定位置加载:

 

 

Configuration configuration = new Configuration().configure("/com/example/hibernatedemo/mapping/hibernate.cfg.xml");

 

2. SessionFactory

SessionFactory 对象用来读取和解析映射文件,并负责创建和管理 Session 对象。

SessionFactory 对象中保存了当前的数据库配置信息、所有映射关系以及 Hibernate 自动生成的预定义 SQL 语句,同时它还维护了 Hibernate 的二级缓存。

一个 SessionFactory 实例对应一个数据库存储源,Hibernate 应用可以从 SessionFactory 实例中获取 Session 实例。

SessionFactory sessionFactory = configuration.buildSessionFactory();
抽取工具类
/**
* 工具类
*/
public class HibernateUtils {
    private static final Configuration configuration;
    private static final SessionFactory sessionFactory;
    //在静态代码块中创建 SessionFactory 对象
    static {
        configuration = new Configuration().configure();
        sessionFactory = configuration.buildSessionFactory();
    }
    //通过 SessionFactory 对象创建 Session 对象
    public static Session openSession() {
        return sessionFactory.openSession();
    }
    public static void main(String[] args) {
//        openSession();
        HibernateUtils hibernateUtils = new HibernateUtils();
    }
}

3. Session

Session 是 Hibernate 应用程序与数据库进行交互时,使用最广泛的接口,它也被称为 Hibernate 的持久化管理器,所有持久化对象必须在 Session 的管理下才可以进行持久化操作。持久化类只有与 Session 关联起来后,才具有了持久化的能力。

//采用 openSession() 方法获取 Session 对象
Session session = sessionFactory.openSession();

Session 对象维护了 Hibernate 的一级缓存,在显式执行 flush 之前,所有的持久化操作的数据都缓存在 Session 对象中。

Session 中的持久化方法
方法描述
save() 执行插入操作
update() 执行修改操作
saveOrUpdate() 根据参数,执行插入或修改操作
delete() 执行删除操作
get() 根据主键查询数据(立即加载)
load() 根据主键查询数据(延迟加载)
createQuery() 获取 Hibernate 查询对象
createSQLQuery() 获取 SQL 查询对象

 

4. Transaction

Transaction 是 Hibernate 提供的数据库事务管理接口,它对底层的事务接口进行了封装。所有的持久化操作(即使是只读操作)都应该在事务管理下进行,因此在进行 CRUD 持久化操作之前,必须获得 Trasaction 对象并开启事务。

Transaction transaction = session.beginTransaction();

常用方法:

方法描述
begin() 该方法用于开启事务
commit() 该方法用于提交事务
rollback() 该方法用于回滚事务

 

@Test
public void test() {
    User user = new User();
    Session session = HibernateUtils.openSession();
    //获取事务对象
    Transaction transaction = session.getTransaction();
    //开启事务
    transaction.begin();
    try {
        //执行持久化操作
        Serializable save = session.save(user);
        //提交事务
        transaction.commit();
    } catch (Exception e) {
        //发生异常回滚事务
        transaction.rollback();
    } finally {
        //释放资源
        session.close();
    }
}

5. Query

Query 是 Hibernate 提供的查询接口,主要用执行 Hinernate 的查询操作

在 Hibernate 应用中使用 Query 对象进行查询,通常需要以下步骤:

  1. 获得 Hibernate 的 Sesssin 对象;

  2. 定义 HQL 语句;

  3. 调用 Session 接口提供的 createQuery() 方法创建 Query 对象,并将 HQL 语句以参数的形式传入到该方法中;

  4. 若 HQL 语句中包含参数,则调用 Query 接口提供的 setXxx() 方法设置参数;

  5. 调用 Query 的 getResultList() 方法,进行查询,并获取查询结果集。

除了 getResultList() 方法外,Query 接口中还包含一些其他的常用方法:

方法描述
setXxx() Query 接口中提供了一系列 setXxx() 方法,用于设置查询语句中的参数。这些方法都需要两个参数,分别是:参数名或占位符位置、参数值。我们需要根据参数类型的不同,分别调用不同的 setXxx() 方法,例如 setString()、setInteger()、setLong()、setBoolean() 和 setDate() 等等。
Iterator iterate(); 该方法用于执行查询语句,并返回一个 Iterator 对象。我们可以通过返回的 Iterator 对象,遍历得到结果集。
Object uniqueResult(); 该方法用户执行查询,并返回一个唯一的结果。使用该方法时,需要确保查询结果只有一条数据,否则就会报错。
int executeUpdate(); 该方法用于执行 HQL 的更新和删除操作。
Query setFirstResult(int var1); 该方法用户设置结果集第一条记录的位置,即设置从第几条记录开始查询,默认从 0 开始。
Query setMaxResults(int var1); 该方法用于设置结果集的最大记录数,通常与 setFirstResult() 方法结合使用,用于限制结果集的范围,以实现分页功能。

HQL 语句还可以进行更新和删除操操作,需要注意的是 HQL 并不支持 insert 操作,想要保存数据请使用 Session 接口提供的 save() 或 saveOrUpate() 方法。

HQLdemo示例:

@Test
    public void testHqlInsert() {
        // 获取 session对象
        Session session = HibernateUtils.openSession();
        // 获取事务对象
        Transaction transaction = session.getTransaction();
        // 开启事务
        transaction.begin();

        // 更新操作
        Query query = session.createQuery("update User SET userName=:username,userId=:userId,email=:email where id=:id");
        // 为更新语句设置参数
        query.setParameter("username", "HQL");
        query.setParameter("userId", "HQL");
        query.setParameter("email", "HQL");
        query.setParameter("id", 4);
        // 执行更新操作
        int i = query.executeUpdate();
        if (i > 0) {
            System.out.println("成功修改了" + i + "条记录");
        }

        // 删除操作
        Query query1 = session.createQuery("delete from User WHERE userId=?1");
        // 为删除语句设置参数
        query1.setParameter(1,"005");
        // 执行删除语句
        int i1 = query1.executeUpdate();
        if (i1 > 0) {
            System.out.println("成功删除了" + i + "条记录");
        }

        //提交事务
        transaction.commit();
        // 释放资源
        session.close();
    }
Hibernate: 
    update
        user 
    set
        user_name=?,
        user_id=?,
        email=? 
    where
        id=?
成功修改了1条记录
Hibernate: 
    delete 
    from
        user 
    where
        user_id=?

9.Hibernate持久化类

持久化对象

“持久化对象”就是持久化类的实例对象,它与数据库表中一条记录相对应,Hibernate 通过操作持久化对象即可实现对数据库表的 CRUD 操作。

持久化对象的状态

在进行数据持久化操作时,持久化对象可能处于不同的状态当中,这些状态可分为三种,分别为瞬时态持久态和脱管态,如下表。

状态别名产生时机特点
瞬时态(transient) 临时态或自由态 由 new 关键字开辟内存空间的对象(即使用 new 关键字创建的对象) 没有唯一标识 OID;未与任何 Session 实例建立关联关系;数据库中也没有与之相关的记录;
持久态(persistent) - 当对象加入到 Session 的一级缓存中时,与 Session 实例建立关联关系时 存在唯一标识 OID,且不为 null;已经纳入到 Session 中管理;数据库中存在对应的记录;持久态对象的任何属性值的改动,都会在事务结束时同步到数据库表中。
脱管态(detached) 离线态或游离态 持久态对象与 Session 断开联系时 存在唯一标识 OID;与 Session 断开关联关系,未纳入 Session 中管理;一旦有 Session 再次关联该脱管对象,那么该对象就可以立马变为持久状态;脱管态对象发生的任何改变,都不能被 Hibernate 检测到,更不能提交到数据库中。

持久化对象的状态转换遵循以下规则

  • 当一个实体类对象通过 new 关键字创建时,此时该对象就处于瞬时态。

  • 当执行 Session 接口提供的 save() 或 saveOrUpate() 方法,将瞬时态对象保存到 Session 的一级缓存中时,该对象就从瞬时态转换为了持久态。

  • 当执行 Session 接口提供的 evict()、close() 或 clear() 方法,将持久态对象与 Session 断开关联关系时,该对象就从持久态转换为了脱管态。

  • 当执行 Session 接口提供的 update()、saveOrUpdate() 方法,将脱管态对象重新与 Session 建立关联关系时,该对象会从脱管态转换为持久态。

  • 直接执行 Session 接口提供的 get()、load() 或 find() 方法从数据库中查询出的对象,是处于持久态的。

  • 当执行 Session 接口提供的 delete() 方法时,持久态对象就会从持久态转换为瞬时态。

  • 由于瞬时态和脱管态对象都不在 Session 的管理范围内,因此一段时间后,它们就会被 JVM 回收。


 

10.Hibernate一级缓存

Hibernate 也提供了缓存机制,当查询数据时,首先 Hibernate 会到缓存中查找,如果找到就直接使用,找不到时才从永久性数据存储源(通常指的是数据库)中检索,因此,把频繁使用的数据加载到缓存中,可以减少应用程序对数据库的访问频次,使应用程序的运行性能得以提升

Hibernate 一级缓存是 Session 级别的缓存,它是由 Hibernate 管理的,不可卸载

Hibernate 一级缓存是由 Session 接口实现中的一系列 Java 集合构成的,其生命周期与 Session 保持一致

Hibernate 一级缓存中存放的数据是数据库中数据的备份,在数据库中数据以数据库记录的形式保存,而在 Hibernate 一级缓存中数据是以对象的形式存放的。

一级缓存的特点

  • 一级缓存是 Hibernate 自带的,默认是开启状态,无法卸载。

  • Hibernate 一级缓存中只能保存持久态对象

  • Hibernate 一级缓存的生命周期与 Session 保持一致,且一级缓存是 Session 独享的,每个 Session 不能访问其他的 Session 的缓存区,Session 一旦关闭或销毁,一级缓存中的所有对象将全部丢失。

  • 当通过 Session 接口提供的 save()、update()、saveOrUpdate() 和 lock() 等方法,对对象进行持久化操作时,该对象会被添加到一级缓存中。

  • 当通过 Session 接口提供的 get()、load() 方法,以及 Query 接口提供的 getResultList、list() 和 iterator() 方法,查询某个对象时,会首先判断缓存中是否存在该对象,如果存在,则直接取出来使用,而不再查询数据库;反之,则去数据库查询数据,并将查询结果添加到缓存中。

  • 当调用 Session 的 close() 方法时,Session 缓存会被清空。

  • 一级缓存中的持久化对象具有自动更新数据库能力。

  • 一级缓存是由 Hibernate 维护的,用户不能随意操作缓存内容,但用户可以通过 Hibernate 提供的方法,来管理一级缓存中的内容,如下表。

返回值类型方法描述
void clear() 该方法用于清空一级缓存中的所有对象。
void evict(Object var1) 该方法用于清除一级缓存中某一个对象。
void flush() throws HibernateException 该方法用于刷出缓存,使数据库与一级缓存中的数据保持一致。

demo示例:

@Test
public void testCacheExist() {
    Session session = HibernateUtils.openSession();
    Transaction transaction = session.getTransaction();
    transaction.begin();
    //第一次查询
    User user = session.get(User.class, 1);
    System.out.println("第一次查询:" + user);
    //第二次查询
    User user2 = session.get(User.class, 1);
    System.out.println("第二次查询:" + user2);
    transaction.commit();
    session.close();
}
Hibernate:
    select
        user0_.id as id1_0_0_,
        user0_.user_id as user_id2_0_0_,
        user0_.user_name as user_nam3_0_0_,
        user0_.password as password4_0_0_,
        user0_.email as email5_0_0_
    from
        user user0_
    where
        user0_.id=?

第一次查询:net.biancheng.www.po.User{id=1, userId='001', userName='admin', password='admin', email='12345678@qq.com'}
第二次查询:net.biancheng.www.po.User{id=1, userId='001', userName='admin', password='admin', email='12345678@qq.com'}

只去数据库中查询了一次。

快照区

Hibernate 的 Session 中,除了一级缓存外,还存在一个与一级缓存相对应的快照区。当 Hibernate 向一级缓存中存入数据(持久态对象)时,还会复制一份数据存入快照区中,使一级缓存和快照区的数据完全相同。

当事务提交时,Hibernate 会检测一级缓存中的数据和快照区的数据是否相同。若不同,则 Hibernate 会自动执行 update() 方法,将一级缓存的数据同步更新到数据库中,并更新快照区,这一过程被称为刷出缓存(flush);反之,则不会刷出缓存。