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
| JDBC | Hibernate | |
|---|---|---|
| 代码量 | 代码繁琐,开发成本较高。 | 代码精简,开发成本较低。 |
| 语言 | 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?
-
一种全自动化的ORM框架,支持双向关系映射,不需要手写sql。
-
提供缓存机制,不用每次都进行查表操作,性能好。
-
支持多种数据库,可移植性好,切换数据库时,修改对应的配置文件即可,不需要因为不同数据库的SQL语法不同,修改大量的sql代码。
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 + '\'' +
'}';
}
}
数据库表与实体类建立关系映射:
<?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>
数据库连接配置文件
<?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'}
插入记录
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'}
Hibernate 工作流程一般分为如下 7 步:
-
Hibernate 启动,Configruation 会读取并加载 Hibernate 核心配置文件和映射文件钟的信息到它实例对象中。
-
通过 Configuration 对象读取到的配置文件信息,创建一个 SessionFactory 对象,该对象中保存了当前数据库的配置信息、映射关系等信息。
-
通过 SessionFactory 对象创建一个 Session 实例,建立数据库连接。Session 主要负责执行持久化对象的增、删、改、查操作,创建一个 Session 就相当于创建一个新的数据库连接。
-
通过 Session 对象创建 Transaction(事务)实例对象,并开启事务。Transaction 用于事务管理,一个 Transaction 对象对应的事务可以包含多个操作。需要注意的是,Hibernate 的事务默认是关闭的,需要手动开启和关闭。
-
Session 接口提供了各种方法,可以对实体类对象进行持久化操作(即对数据库进行操作),例如 get()、load()、save()、update()、saveOrUpdate() 等等,除此之外,Session 对象还可以创建Query 对象 或 NativeQuery 对象,分别使用 HQL 语句或原生 SQL 语句对数据库进行操作。
-
对实体对象持久化操作完成后,必须提交事务,若程序运行过程中遇到异常,则回滚事务。
-
关闭 Session 与 SessionFactory,断开与数据库的连接,释放资源。
<?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>
| 描述 | 是否为必需属性 | |
|---|---|---|
| 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 | 事务是否自动提交 |
<?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.实体类与数据库表建立映射关系。
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 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();
| 描述 | |
|---|---|
| save() | 执行插入操作 |
| update() | 执行修改操作 |
| saveOrUpdate() | 根据参数,执行插入或修改操作 |
| delete() | 执行删除操作 |
| get() | 根据主键查询数据(立即加载) |
| load() | 根据主键查询数据(延迟加载) |
| createQuery() | 获取 Hibernate 查询对象 |
| createSQLQuery() |
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();
}
}
Query 是 Hibernate 提供的查询接口,主要用执行 Hinernate 的查询操作。
在 Hibernate 应用中使用 Query 对象进行查询,通常需要以下步骤:
-
获得 Hibernate 的 Sesssin 对象;
-
定义 HQL 语句;
-
调用 Session 接口提供的 createQuery() 方法创建 Query 对象,并将 HQL 语句以参数的形式传入到该方法中;
-
若 HQL 语句中包含参数,则调用 Query 接口提供的 setXxx() 方法设置参数;
-
调用 Query 的 getResultList() 方法,进行查询,并获取查询结果集。
除了 getResultList() 方法外,Query 接口中还包含一些其他的常用方法:
| 描述 | |
|---|---|
| setXxx() | Query 接口中提供了一系列 setXxx() 方法,用于设置查询语句中的参数。这些方法都需要两个参数,分别是:参数名或占位符位置、参数值。我们需要根据参数类型的不同,分别调用不同的 setXxx() 方法,例如 setString()、setInteger()、setLong()、setBoolean() 和 setDate() 等等。 |
| Iterator |
该方法用于执行查询语句,并返回一个 Iterator 对象。我们可以通过返回的 Iterator 对象,遍历得到结果集。 |
| Object uniqueResult(); | 该方法用户执行查询,并返回一个唯一的结果。使用该方法时,需要确保查询结果只有一条数据,否则就会报错。 |
| int executeUpdate(); | 该方法用于执行 HQL 的更新和删除操作。 |
| Query |
该方法用户设置结果集第一条记录的位置,即设置从第几条记录开始查询,默认从 0 开始。 |
| Query |
HQL 语句还可以进行更新和删除操操作,需要注意的是 HQL 并不支持 insert 操作,想要保存数据请使用 Session 接口提供的 save() 或 saveOrUpate() 方法。
@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=?
持久化对象
“持久化对象”就是持久化类的实例对象,它与数据库表中一条记录相对应,Hibernate 通过操作持久化对象即可实现对数据库表的 CRUD 操作。
持久化对象的状态
在进行数据持久化操作时,持久化对象可能处于不同的状态当中,这些状态可分为三种,分别为瞬时态、持久态和脱管态,如下表。
| 别名 | 产生时机 | 特点 | |
|---|---|---|---|
| 瞬时态(transient) | 临时态或自由态 | 由 new 关键字开辟内存空间的对象(即使用 new 关键字创建的对象) | 没有唯一标识 OID;未与任何 Session 实例建立关联关系;数据库中也没有与之相关的记录; |
| 持久态(persistent) | - | 当对象加入到 Session 的一级缓存中时,与 Session 实例建立关联关系时 | 存在唯一标识 OID,且不为 null;已经纳入到 Session 中管理;数据库中存在对应的记录;持久态对象的任何属性值的改动,都会在事务结束时同步到数据库表中。 |
| 脱管态(detached) | 离线态或游离态 | 持久态对象与 Session 断开联系时 |
持久化对象的状态转换遵循以下规则:
-
当一个实体类对象通过 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);反之,则不会刷出缓存。