首先我们应该弄清什么是 hibernate 缓存: hibernate 缓存是指为了降低应用程序对物理数据源的访问频次,从而提高应用程序的运行性能的一种策略。我们要将这个跟计算机内存或者 cpu 的缓存区分开。
既然是基于查询分析 hibernate 一级缓存,我们就来分析分析 hibernate 查询方式
我们通过查看 hibernate 的 api 文档找到了 session 接口,并重点看了 get() 方法,我们主要使用一下两种 get() 方法:
通过传入由实体类获得的 Class 类对象(姑且叫做类类型)和该类的唯一标识符两个参数,返回一个 Object 类型的查询对象。
通过传入实体类名和该类对象的唯一标识符两个参数,返回一个 Object 类型的查询对象。
代码示例:
运行结果:
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- 学号:1 姓别:女 姓名:小美
- 学号:1 姓别:女 姓名:小美
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- 学号:1 姓别:女 姓名:小美
分析:在同一个 session 对象的条件下查询同一表格记录,hibernate 解析的 SQL 语句只会执行一次,重新获得一个 session 对象后,再去查询相同的表格记录时,hibernate 解析而成的 SQL 语句会在执行一次。
我们不难得出:在同一个 session 对象的情况下,使用 get() 方法查询相同的对象会使用到缓存(一级缓存),不同的 session 对象在查询相同对象正常情况下是不会使用缓存。
我们通过查看 hibernate 的 api 文档找到了 session 接口,并重点看了 load() 方法,我们主要使用一下两种 load() 方法:
通过传入由实体类获得的 Class 类对象(姑且叫做类类型)和该类的唯一标识符两个参数,返回一个 Object 类型的查询对象。
通过传入实体类名和该类对象的唯一标识符两个参数,返回一个 Object 类型的查询对象。
代码示例:
运行结果:
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- 学号:1 姓别:女 姓名:小美
- 学号:1 姓别:女 姓名:小美
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- 学号:1 姓别:女 姓名:小美
分析:在同一个 session 对象的条件下查询同一表格记录,hibernate 解析的 SQL 语句只会执行一次,重新获得一个 session 对象后,再去查询相同的表格记录时,hibernate 解析而成的 SQL 语句会在执行一次。
我们不难得出:在同一个 session 对象的情况下,使用 load() 方法查询相同的对象会使用到缓存(一级缓存),不同的 session 对象在查询相同对象正常情况下是不会使用缓存。
我们可以总结得到,load() 函数的查询流程和 get() 函数的查询流程基本相同。
我们通过查看 hibernate 的 api 文档找到了 session 接口,找到 createQuery(String HQL) 方法,该方法的返回值类型是一个 Query(查询),于是,我们找到 Query 接口,我们找到了两个方法,是将查询结果返回的。
以 List 的方式返回查询结果
以迭代器的方式返回查询结果
1)有 select 子句
运行结果:
- Hibernate:
- select
- students2x0_.SID as col_0_0_,
- students2x0_.SNAME as col_1_0_,
- students2x0_.SGENDER as col_2_0_
- from
- STUDENTS2 students2x0_
- 学号:1 姓名:小美 性别:女
- 学号:2 姓名:小泽 性别:男
- 学号:3 姓名:小敏 性别:女
- Hibernate:
- select
- students2x0_.SID as col_0_0_,
- students2x0_.SNAME as col_1_0_,
- students2x0_.SGENDER as col_2_0_
- from
- STUDENTS2 students2x0_
- 学号:1 姓名:小美 性别:女
- 学号:2 姓名:小泽 性别:男
- 学号:3 姓名:小敏 性别:女
2)没有 select 子句
运行结果:
- Hibernate:
- select
- students2x0_.SID as SID1_1_,
- students2x0_.SNAME as SNAME2_1_,
- students2x0_.SGENDER as SGENDER3_1_
- from
- STUDENTS2 students2x0_
- 学号:1 姓名:小美 性别:女
- 学号:2 姓名:小泽 性别:男
- 学号:3 姓名:小敏 性别:女
- Hibernate:
- select
- students2x0_.SID as SID1_1_,
- students2x0_.SNAME as SNAME2_1_,
- students2x0_.SGENDER as SGENDER3_1_
- from
- STUDENTS2 students2x0_
- 学号:1 姓名:小美 性别:女
- 学号:2 姓名:小泽 性别:男
- 学号:3 姓名:小敏 性别:女
分析:相同 session,甚至相同 query 对象情况下,查询相同的对象,hibernate 解析的 SQL 语句在数据库执行了两次。
很明显能看出:session.createQuery(hql).list() 方法,不会使用缓存。
代码示例:
运行结果:
- *************带有select子句的查询*********************
- Hibernate:
- select
- students2x0_.SID as col_0_0_,
- students2x0_.SNAME as col_1_0_,
- students2x0_.SGENDER as col_2_0_
- from
- STUDENTS2 students2x0_
- 学号:1 姓名:小美 性别:女
- 学号:2 姓名:小泽 性别:男
- 学号:3 姓名:小敏 性别:女
- 同一个session并且同一个query对象下查询相同对象:
- Hibernate:
- select
- students2x0_.SID as col_0_0_,
- students2x0_.SNAME as col_1_0_,
- students2x0_.SGENDER as col_2_0_
- from
- STUDENTS2 students2x0_
- 学号:1 姓名:小美 性别:女
- 学号:2 姓名:小泽 性别:男
- 学号:3 姓名:小敏 性别:女
- **************不带select子句的查询**********************
- Hibernate:
- select
- students2x0_.SID as col_0_0_
- from
- STUDENTS2 students2x0_
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- 学号:1 姓别:女 姓名:小美
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- 学号:2 姓别:男 姓名:小泽
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- 学号:3 姓别:女 姓名:小敏
- 在同一session同一query1对象下查询相同的对象:
- Hibernate:
- select
- students2x0_.SID as col_0_0_
- from
- STUDENTS2 students2x0_
- 学号:1 姓别:女 姓名:小美
- 学号:2 姓别:男 姓名:小泽
- 学号:3 姓别:女 姓名:小敏
- 在同一个session但是不是一个query对象下查询相同对象:
- Hibernate:
- select
- students2x0_.SID as col_0_0_
- from
- STUDENTS2 students2x0_
- 学号:1 姓别:女 姓名:小美
- 学号:2 姓别:男 姓名:小泽
- 学号:3 姓别:女 姓名:小敏
- 在不同的session中,查询相同的对象:
- Hibernate:
- select
- students2x0_.SID as col_0_0_
- from
- STUDENTS2 students2x0_
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- 学号:1 姓别:女 姓名:小美
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- 学号:2 姓别:男 姓名:小泽
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- 学号:3 姓别:女 姓名:小敏
分析:以迭代器方式返回的查询,执行我们分成使用 select 子句和没有使用 select 子句的查询:
1)使用了 select 子句的查询,是不会使用缓存的
2)不使用 select 子句的查询,情况可以分为在同一个 session 下和不同的 session 下查询相同的对象。在同一个 session 下,第一次查询缓存中不存在的对象时,会先到数据库中查询要查对象的主键,然后依靠主键使用 where 子句限定主键,然后一一按照主键到数据库中执行 SQL 语句查询对象;再次查询相同对象时,会现在缓存中查询对象的编号,找到相同编号的返回,找不到的,再到数据库去按照编号查找。在不同 session 下,缓存一般不能使用。
1、hibernate 一级缓存也称为 "会话级缓存"、"session 缓存"。
2、一级缓存的生命周期和 session 相同,session 销毁,缓存也销毁。
3、一级缓存数据的使用范围,或者说是作用域为当前会话。
4、hibernate 一级缓存的 API
一级缓存无法取消,用两个方法管理。
evict():用于将某个对象从 session 中的一级缓存中清除。
clear():用于将一级缓存中的对象全部清除。
运行结果:
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- 第一遍查询:
- 学号:1 姓名:小美 性别:女
- 学号:2 姓名:小泽 性别:男
- 学号:3 姓名:小敏 性别:女
- 先使用evict()方法,然后在查询相同session下之前查过的对象:
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- 学号:1 姓名:小美 性别:女
- 使用clear()方法,然后再查询相同session下之前查过的对象:
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- Hibernate:
- select
- students2x0_.SID as SID1_1_0_,
- students2x0_.SNAME as SNAME2_1_0_,
- students2x0_.SGENDER as SGENDER3_1_0_
- from
- STUDENTS2 students2x0_
- where
- students2x0_.SID=?
- 学号:1 姓名:小美 性别:女
- 学号:2 姓名:小泽 性别:男
- 学号:3 姓名:小敏 性别:女
(1)一级缓存的数据的作用范围为一个 session,缓存会随着 session 的销毁而销毁。
(2)其中通过 get()、load()、和以 Iterator(迭代器)方式返回无 select 子句查询都会使用到缓存,但是通过以 list 方式和 Iterator(迭代器)方式返回的有 select 子句的查询不会使用缓存。
(3)其中以 Iterator(迭代器)方式返回的 hibernate 查询都是先从数据库中查询对象的编号,然后到缓存中查找匹配的编号,找到了直接返回,找不到通过 where 子句限定以编号去数据库中查找,然后返回。
一级缓存查询的流程图:
来源: http://www.cnblogs.com/xiaotiaosi/p/6498122.html