缓存定义:
缓存是在内存中专门分配的空间,用于存储原本应存储在硬盘上的数据,以便加快数据访问速度。所有查询操作都可能将数据存入缓存中,从而减少对硬盘存储器的频繁访问,提高系统性能。
一级缓存(Session 级别缓存):
-
一级缓存是线程级别的缓存,与每个 Hibernate Session 相关联。
-
查询时,除非使用
get
或load
方法,否则不会优先从缓存中获取数据,但在对象实例化过程中会检查缓存是否存在匹配的对象。 -
update(user)
方法会更新缓存中的对象。 -
query.executeUpdate()
不会更新缓存。 -
load
方法流程:首先检查一级缓存 -> 检查二级缓存 -> 若均未命中,则访问数据库 -> 数据填充至一级缓存(可能也填充至二级缓存)并返回代理对象。整理了一份面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记的【点击此处即可】即可免费获取
-
get
方法类似,若缓存中有匹配对象,则直接返回缓存中的数据。 -
缓存特性:持久化对象会自动同步其变化到数据库中。
-
快照:在一级缓存旁边维护着对象数据的备份,确保数据库和一级缓存数据的一致性。当一级缓存数据被修改且事务提交时,一级缓存会被刷新,并执行更新操作将缓存数据更新至数据库。
-
更新与
saveOrUpdate
方法:update
方法针对已具有持久化标识的对象执行更新操作。saveOrUpdate
方法会根据对象是否有持久化标识决定执行更新或插入操作。
-
save
、persist
与merge
的区别:save
方法:即使在调用前设置了 ID 值,也会遵循数据库的 ID 生成策略,而不是使用用户设置的 ID。persist
方法:如果设置了 ID,会尝试查找数据库中对应 ID 的记录,不存在则插入,存在则抛出异常。merge
方法:对于带有 ID 的对象视为游离态对象处理,如果在数据库中找到匹配的 ID,则执行更新操作;如果没找到,则执行插入;若未设置 ID,则视作瞬态对象。
-
flush
与update
区别:flush
:手动强制刷新缓存,使其内容与数据库同步。update
:在事务提交时,会自动触发flush
操作,将缓存中的更改同步至数据库。
-
lock
与update
区别:lock
:将一个尚未更改过的托管对象变为持久化状态。update
:将一个已更改的托管对象转变为持久化状态。
-
clear
与evict
区别:clear
:清空 Session 缓存中的所有数据。evict
:从 Session 缓存中移除指定的持久化对象。
二级缓存
二级缓存是进程级别的缓存,它的键(key)通常是对象的唯一标识符(如ID),值(value)则是对象本身。这种缓存位于SessionFactory级别,因此能够在不同Session之间共享数据,使得多个Session能够共用缓存内容。
SessionFactory缓存构成
SessionFactory缓存分为两个部分:
-
内置缓存:
- 这是一个只读的Map结构,用于存储Hibernate框架所需的配置信息、预定义的HQL语句等内部数据。
- 内置缓存仅供Hibernate框架内部使用,外部无法直接操作,也不支持卸载。
-
外置缓存(二级缓存):
- 使用另一个Map来存储用户自定义的、需要跨Session共享的数据。
- 外置缓存默认情况下并未开启,Hibernate仅提供缓存规范和接口,具体的实现通常由第三方缓存提供者完成,例如EHCache、Redis等。
- 当开启二级缓存后,它可以被不同的Session访问和共享,并且在不需要使用时可以卸载或重新配置。
缓存访问方法
-
load
、get
以及iterate
方法都会利用二级缓存来提升数据获取效率。其中,iterate
方法虽然底层也是使用load
,但它会在查询过程中发送SQL查询ID值,然后根据ID逐个加载对象。 -
当查询使用
query.list()
方法时,如果查询缓存已启用,那么查询的结果将根据SQL语句作为键,ID作为值存储在缓存中。在后续相同的查询条件下,可以直接从缓存中获取ID,进而逐个加载对象。
二级缓存组成要素
-
类级别缓存(Class Cache):存储对象自身的散列数据,即非集合属性的内容。
-
集合级别缓存(Set Cache):用于存放关联对象的OID(对象标识符),主要针对对象集合属性。
-
时间戳缓存:记录对象最后更新的时间戳信息,用于判断缓存是否过期或数据是否脏读。
-
查询缓存(Query Cache):作为二级缓存的一部分,有时也称为三级缓存,它基于SQL查询结果进行缓存。查询缓存将查询语句及其结果进行绑定,当同一查询被执行时,可以从缓存中快速获取结果。
适用场景
二级缓存适用于那些访问频繁但改动较少的数据,允许一定程度的并发访问,并且数据总量相对有限的情况。
缓存内部结构图
二级缓存的使用方法
-
XML配置方式:通过在Hibernate的配置文件中添加特定的属性和配置来启用二级缓存。
-
注解方式:在实体类上使用
@Cache
注解来声明使用二级缓存,可以选择缓存并发策略,如:@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
表示可读写缓存。@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
表示只读缓存。
查询缓存的启用与使用
-
开启查询缓存:在Hibernate配置文件中设置
<property name="cache.use_query_cache">true</property>
来开启查询缓存功能。 -
在DAO层中使用查询缓存:在执行查询时,需要在Query对象上调用
query.setCacheable(true)
来启用查询缓存,这样查询结果将在符合条件的情况下从二级缓存中获取,而非直接从数据库查询。查询缓存默认是禁用的,需要显式开启才能使用。