首页 > Hibernate 阅读▄▓:595

Hibernate一级缓存博猫

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

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

在使用 Hibernate 查询对象时,首先会使用对象的 OID 值在 Hibernate 的一级缓存中查找,如果找到匹配的对象▓▓,则直接将该对象从一级缓存中取出使用;如果没有找到匹配的对象,则会去数据库中查询对应的数据▄■▄。当从数据库中查询到所需数据时,该数据信息会存储到一级缓存中。由此可知■■■,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() 方法▄▓。

以上就是 Hibernate 一级缓存的刷出情况▓█▄■。对于刚接触 Hibernate 框架的读者来说并不是很容易理解,为了帮助读者更好地理解 Session 的一级缓存,下面通过具体案例演示一级缓存的使用▄■▓。

以 goods 表为例,此时 goods 表中的数据如图 1 所示。
goods表查询结果
图 1  goods表查询结果

在 GoodsTest 类中添加一个名为 test2() 的方法▄▓,使用该方法证明一级缓存的存在,其代码如下所示:
// 证明一级缓存的存在
@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 语句▄■▄,这是因为该对象是在一级缓存中获取的。

为了验证上面的描述,接下来在 7 行设置断点■■■,用 Debug 方式执行 test2() 方法。程序进入断点后,按 F6 键执行 System.out.println(goods1); 语句后▄■▄■,控制台的显示结果如图 2 所示。

输出结果
图 2  输出结果

从图 2 的显示结果中可以看出,执行第一次 get() 方法后▓▄▓▄,Hibernate 会向数据库中发出一条 SQL 语句,这说明 goods1 对象是从数据库中查询的。程序继续向下执行第二个输出语句时▄▓,控制台显示结果如图 3 所示▓█▄■。

输出结果
图 3  输出结果

从图 3 的显示结果中可以看出,goods2 对象的查询结果被直接输出了,这说明第二次调用 get() 方法获取 goods2 对象时没有查询数据库▄■▓,而是直接从一级缓存中获取了 goods2 对象。

Java交流群:739993120(我们会不定期在群内分享Java知识▄▓,上传Java资料)

编程帮,一个分享编程知识的公众号▓█。跟着站长一起学习,每天都有进步。

通俗易懂█■▄,深入浅出,一篇文章只讲一个知识点。

文章不深奥███,不需要钻研,在公交、在地铁▓▓、在厕所都可以阅读,随时随地涨姿势。

文章不涉及代码▄■▄,不烧脑细胞,人人都可以学习。

当你决定关注「编程帮」■■■,你已然超越了90%的程序员!

编程帮二维码
微信扫描二维码关注