02.Hibernate一级缓存详解

本文深入探讨了Hibernate的一级缓存,包括其概念、特点、操作(刷出、清除、刷新)以及对象状态的转换。通过案例展示了如何证明一级缓存的存在,并解释了Session对象的方法、事务隔离级别和对象的持久化状态。最后,提到了Hibernate配置文件和C3P0连接池的设置。
摘要由CSDN通过智能技术生成

02.Hibernate一级缓存详解

1、缓存(一级缓存、Session缓存)

概念

主要:根据OID来进行判断

Hibernate中的缓存分为一级缓存和二级缓存,这两个级别的缓存都位于持久化层,并且存储的都是数据库数据的备份。其中一级缓存是 Hibernate 的内置缓存,在前面的学习中已经使用过。本节将针对 Hibernate 的一级缓存进行详细讲解。

一级缓存其实就是 Session 缓存。Session 缓存是一块内存空间,用于存储与管理 Java 对象。

在使用 Hibernate 查询对象时,首先会使用对象的 OID 值在 Hibernate 的一级缓存中查找,如果找到匹配的对象,则直接将该对象从一级缓存中取出使用;如果没有找到匹配的对象,则会去数据库中查询对应的数据。当从数据库中查询到所需数据时,该数据信息会存储到一级缓存中。由此可知,Hibernate 一级缓存的作用就是减少对数据库的访问次数。

特点

1)当应用程序调用 Session 接口的 save()、update()、saveOrUpdate() 时,如果 Session 缓存中没有相应的对象,则 Hibernate 就会自动把从数据库中查询到的相应对象信息加入到一级缓存中。

2)当调用 Session 接口的 load()、get() 方法,以及 Query 接口的 list()、iterator() 方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果缓存中没有要查询的对象,则再去数据库中查询对应对象,并添加到一级缓存中。

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

4)Session 能够在某些情况下,按照缓存中对象的变化,执行相关的 SQL 语句同步更新数据库,这一过程被称为刷出缓存(flush)。

在默认情况下,Session 在如下几种情况中会刷出缓存。

1)当应用程序调用 Transaction 的 commit() 方法时,该方法先刷出缓存(调用 session.flush() 方法),然后再向数据库提交事务(调用 commit() 方法)。

2)当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生了变化,会先刷出缓存,以保证查询结果能够反映持久化对象的最新状态。

3)调用 Session 的 flush() 方法。

案例1:证明一级缓存的存在

// 证明一级缓存的存在
@Test
public void test2() {
   
    Session session = HibernateUtils.getSession(); // 得到session对象
    session.beginTransaction();
    // 获取goods1对象时,由于一级缓存中没有数据,所以会发送SQL语句,查询数据库中的内容
    Goods goods1 = (Goods) session.get(Goods.class, 1);
    System.out.println(goods1);
    // 获取goods2对象时,不会发出SQL语句,会从Session缓存中获取数据
    Goods goods2 = (Goods) session.get(Goods.class, 1);
    System.out.println(goods2);
    session.getTransaction().commit();
    session.close();
}

在上述代码中,第一次执行 get() 方法时,由于一级缓存中不存在 id 为 1 的 Goods 对象,所以 Hibernate 会发出 SQL 语句查询数据库中 id 为 1 的数据。查到后,会将该数据信息保存到一级缓存中。当再次调用 get() 方法获取该对象时,此时将不会发出 SQL 语句,这是因为该对象是在一级缓存中获取的。

案例2:一级缓存的常用操作

1. 刷出(flush)

一级缓存刷出功能是指调用 Session 的 flush() 方法时会执行刷出缓存的操作。

// 刷出
@Test
public void test4() {
   
    Session session = HibernateUtils.getSession(); // 得到session对象
    session.beginTransaction();
    Goods goods = (Goods) session.get(Goods.class, 2);
    goods.setPrice(5.5);
    session.flush(); // 执行刷出操作,此时会发送update语句
    session.getTransaction().commit();
    session.close();
}

在 flush() 方法处设置断点,利用 Debug 模式运行程序。当程序停止在断点处时,控制台中会显示查询 Goods 对象时所发出的 select 语句。当程序向下执行完 session.flush() 语句时,控制台会输出 update 语句

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MepcE4Uj-1609491479896)(images1\img03.png)]

解释:发出了 update 语句,这说明在提交事务前,Hibernate 程序会默认先执行 flush() 方法。

2. 清除(clear)

程序在调用 Session 的 clear() 方法时,可以执行清除缓存数据的操作。

// 清除
@Test
public void test5() {
   
    Session session = HibernateUtils.getSession(); // 得到session对象
    session.beginTransaction();
    Goods goods = (Goods) session.get(Goods.class, 2);
    System.out.println(goods);
    goods.setPrice(6.5);
    session.clear(); // 清空一级缓存
    session.getTransaction().commit();
    session.close();
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eJjrWyJ8-1609491479897)(F:\S3课程\md文档总结笔记(ycj)\Hibernate_md总结文档\images1\img04.png)]

解释:从图 2 中可以看出,执行后的 test5() 方法只输出了 select 语句,而没有输出 update 语句。同时,查看数据库时,会发现数据库中的数据也没有发生变化。这是因为在执行 clear() 方法时,清空了一级缓存中的数据,所以 Goods 对象的修改操作并没有生效。

需要注意的是,如果将上述方法中的 session.clear() 方法更改为 session.evict(goods)方法,也可以实现同样的效果。这两个方法的区别是:clear() 方法是清空一级缓存中所有的数据,而 evict() 方法是清除一级缓存中的某一个对象。

3. 刷新(refresh)

程序在调用 Session 的 refresh() 方法时,会重新查询数据库,并更新 Hibernate 快照区和一级缓存中的数据。

// 刷新
@Test
public void test6() {
   
    Session session = HibernateUtils.getSession(); // 得到session对象
    session.beginTransaction();
    Goods goods = (Goods) session.get(Goods.class, 2);
    goods.setPrice(7.5);
    session.refresh(goods); // 查询数据库,恢复快照和一级缓存中的数据
    session.getTransaction().commit();
    session.close();
}

2、Session对象的方法

save:保存对象
persist():保存一个对象,跟save作用一样
	*如果手动设置了ID,则save方法会忽略ID,而persist方法则会抛出一个异常
get:根据OID获取对象
load:加载一个对象,跟get作用一样
	1、get会立即执行查询,而load不会立即执行查询,在用到该对象的时候才会去执行查询操作(懒加载)
	2、load加载之后,如果session被管理,则直接抛出异常
	3、如果数据库中没有与之对应的结果,get回返回一个null,而load方法会抛出异常
clear:清空缓存
refresh:重新加载某个对象
evict:可以将某个被session管理的持久化对象,从session中移除,使其变为游离对象
close:关闭session
	
update:更新对象(游离),该对象会转变为持久化对象
	
delete:从数据库中删除一个对象
	
saveOrUpdate:系统会判断该对象,如果是临时对象,就会执行保存操作,如果是游离对象,则执行更新操作
	
flush:发送让session对象SQL语句

3、事务的隔离级别(可重复读)

TRANSACTION_NONE(0):不使用事务的隔离级别
TRANSACTION_READ_UNCOMMITED(1):读未提交:脏读、不可重复读、幻读
TRANSACTION_READ_COMMITED(2):读已提交:不可重复读、幻读
TRANSACTION_PREPETABLE_READ(4):可重复度:幻读
TRANSACTION_SERIALIZABLE(8):序列化
脏读:读取到了未提交的数据
不可重复读:两次读取结果不一致
幻读:数据记录数量发生了改变
在Hibernate中设置事务的隔离级别

4、对象的状态

持久化对象的状态及状态转换

在 Hibernate中,持久化对象是存储在一级缓存当中的,一级缓存指 Session 级别的缓存,它可以根据缓存中的持久化对象的状态改变同步更新数据库。

Hibernate 是持久层的 ORM 框架,专注于数据的持久化工作。在进行数据持久化操作时,持久化对象可能处于不同的状态当中。这些状态可分为三种,分别为瞬时态、持久态和脱管态。下面分别针对这三种状态进行简单介绍。

1)瞬时态(transient)

瞬时态也称为临时态或者自由态,瞬时态的对象是由 new 关键字开辟内存空间的对象,不存在持久化标识 OID(相当于主键值),且未与任何的 Session 实例相关联,在数据库中也没有记录,失去引用后将被 JVM 回收。瞬时对象在内存孤立存在,它是携带1信息的载体,不和数据库的数据有任何关联关系。

2)持久态(persistent)

持久态的对象存在一个持久化标识 OID,当对象加入到 Session 缓存中时,就与 Session 实例相关联。它在数据库中存在与之对应的记录,每条记录只对应唯一的持久化对象。需要注意的是,持久态对象是在事务还未提交前变成持久态的。

3)脱管态(detached)

脱管态也称离线态或者游离态,当持久化对象与 Session 断开时就变成了脱管态,但是脱管态依然存在持久化标识 OID,只是失去了与当前 Session 的关联。需要注意的是,脱管态对象发生改变时 Hibernate 是不能检测到的。

在 Hibernate 运行时,持久化对象的三种状态是可以通过一系列的方法进行转换的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PGxcNUvn-1609491479898)(images1/img02.png)]

解释:当一个对象通过 new 关键字创建后,该对象处于瞬时态;当对瞬时态对象执行 Session 的 save() 或 saveOrUpdate() 方法后,该对象将被放入 Session 的一级缓存中,此时该对象处于持久态。

当对持久态对象执行 evict()、close() 或 clear() 操作后,对象会进入脱管态。

当直接执行 Session 的 get()、load()、find() 或 iterate() 等方法从数据库中查询出对象时,查询到的对象也会处于持久态。

当对数据库中的纪录进行 update()、saveOrUpdate() 以及 lock() 等操作后,此时脱管态的对象就过渡到持久态;由于瞬时态和脱管态的对象不在 session 的管理范围内,所以会在一段时间后被 JVM 回收。

对象的状态(最核心的在于对象的OID是否为空,如果OID为空,则一定是临时对象)

​ 1.临时对象(瞬时态):

​ 自己New的对象
​ 不存在于数据库中
​ 不存在于Session中
​ OID为NULL

​ 2.持久化对象(持久态):

​ 通过get等方法从数据库中取出来的对象

​ 3.游离对象(游离、脱管、离线态):

​ 存在于数据库中,但是并未被session管理的对象

​ 4.*删除对象(删除态):

​ 本来存在于数据库中,后来被删除了

5、Hibernate hibernate.cfg.xml文件和C3P0连接池的配置

Hibernate hibernate.cfg.xml文件配置

Hibernate的配置文件包含了数据库连接的相关信息,以及映射文件的基本信息。通常情况下,配置文件默认放在 src 目录下,发布后,该文件会在项目的 WEB-INF/classes 路径下。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- 指定方言 -->
        <property name="dialect">
            org.hibernate.dialect.MySQL5Dialect
        </property>
        <!-- 链接数据库url -->
        <property name="connection.url">
              <![CDATA[jdbc:mysql://localhost:3306/hibernate?useUnicode=true&characterEncoding=utf-8]]>
        </property>
        <!-- 连接数据库的用户名 -->
        <property name="connection.username">
            root
        </property>
        <!-- 数据库的密码 -->
        <property name="connection.password">
            1128
        </property>
        <!-- 数据库驱动 -->
        <property name="connection.driver_class">
            com.mysql.jdbc.Driver
        </property>
        <!-- 其他配置 -->
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值