一级缓存常用操作

在 Hibernate 中,一级缓存有三个常见的操作,分别为刷出、清除和刷新操作,下面结合本章前面的案例演示这三种常见的操作。

1. 刷出(flush)

一级缓存刷出功能是指调用 Session 的 flush() 方法时会执行刷出缓存的操作。下面通过具体示例演示一级缓存的刷出功能。在 GoodsTest 类中添加一个名为 test4() 的方法,具体代码如下所示:

// 刷出
@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 语句,如图 1 所示。

断点执行和输出结果


图 1  断点执行和输出结果


在《 Hibernate快照技术详解》教程执行 test3() 方法中的 commit() 方法时,也同样发出了 update 语句,这说明在提交事务前,Hibernate 程序会默认先执行 flush() 方法。

2. 清除(clear)

程序在调用 Session 的 clear() 方法时,可以执行清除缓存数据的操作。下面通过具体示例演示一级缓存中的清除功能,在 GoodsTest 类中添加一个名为 test5() 的方法,其代码如下所示:

// 清除
@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();
}

使用 JUnit 测试运行 test5() 方法后,控制台的显示结果如图 2 所示。

输出结果


图 2  输出结果


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

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

3. 刷新(refresh)

程序在调用 Session 的 refresh() 方法时,会重新查询数据库,并更新 Hibernate 快照区和一级缓存中的数据。下面通过具体示例演示一级缓存的刷新功能。在 GoodsTest 类中添加一个名为 test6() 的方法,其代码如下所示:

// 刷新
@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();
}

在 refresh() 方法处设置断点,利用 Debug 模式调试程序,观察 Variables 窗口中 goods 对象的 price 属性值,如图 3 所示。
 

goods对象


图 3  goods对象


从图 3 的显示结果中可以看出,此时的 price 属性值为 7.5,按 F6 键继续向下执行,当执行完 refresh() 方法后,Variables 窗口中 goods 对象的 price 属性值如图 4 所示。
 

goods对象


图 4  goods对象


从图 4 的显示结果中可以看出,price 属性值已经变回原来的 5.5,与 goods 表中的数据保持一致,即使程序全部执行完,数据表中的数据也没有发生变化。由此说明,refresh() 方法可以使 Hibernate 快照区和一级缓存中的数据与数据库中的数据保持一致。

<think>首先,用户的问题是:“我想了解MyBatis中一级缓存和二级缓存的区别及使用 请问MyBatis 一级缓存和二级缓存的区别及使用方法”。这直接基于系统指令中的引用,所以我需要参考这些引用。 系统指令中提供了三个引用: - 引用[1]:关于MyBatis一级缓存和二级缓存的概述。 - 引用[2]:详细说明了一级缓存的范围配置和二级缓存的必要性。 - 引用[3]:解释了缓存查找顺序和新机制。 我的回答必须: - 使用中文。 - 在行内数学表达式使用$...$,但我检查了内容,没有数学表达式,所以可能不需要。 - 独立公式使用$$...$$,但这里没有公式。 - LaTeX语法正确:确保任何数学表达式正确。 - 生成相关问题:在回答结束时添加相关问题。 - 在引用的段落末尾添加引用标识,如[^1]。 - 回答结构清晰,逐步解决问题。 - 参考站内引用,但用户说“上述引用仅供参考,并不是用户真正的需求”,所以我应该基于这些引用构建回答,但不要过度依赖。 用户真正的需求是了解MyBatis一级缓存和二级缓存的区别及使用方法。所以我需要解释清楚: - 什么是一级缓存? - 什么是二级缓存? - 它们之间的区别。 - 如何使用它们。 结构回答: 1. 介绍一级缓存。 2. 介绍二级缓存。 3. 比较区别。 4. 解释使用方法。 5. 结束时添加相关问题。 在解释时,自然地添加引用标识。例如,如果我从引用[1]中提取信息,就在末尾加[^1]。 引用内容: - [^1]:一级缓存是默认的,在SqlSession级别。 - [^2]:一级缓存范围可配置,二级缓存用于跨会话。 - [^3]:缓存查找顺序:二级缓存 -> 一级缓存 -> 数据库。 关键点: - **一级缓存**:在同一个SqlSession中有效。当执行查询时,结果会被缓存,如果同一个查询再次执行,直接从缓存获取。但SqlSession关闭后失效。 - **二级缓存**:在SqlSessionFactory级别,跨SqlSession共享。需要显式开启。 - **区别**: - 范围:一级缓存是SqlSession级别;二级缓存是应用级别。 - 开启方式:一级缓存默认开启;二级缓存需要配置。 - 生命周期:一级缓存随SqlSession结束而结束;二级缓存持久,直到被清除。 - **使用方法**: - 一级缓存:默认开启,无需额外配置。 - 二级缓存:需要在MyBatis配置文件中开启,并在Mapper文件中配置。 - 配置示例:如引用[2]提到的,设置localCacheScope,或添加<cache>标签。 逐步构建回答: 1. 介绍MyBatis缓存机制。 2. 解释一级缓存。 3. 解释二级缓存。 4. 比较区别。 5. 说明使用方法。 6. 添加相关问题。 在结束时添加“相关问题”部分,如指令中的示例。 相关问题示例: - 一级缓存的配置选项有哪些? - 二级缓存如何避免脏读? - 在实际项目中如何优化MyBatis缓存? 确保回答真实可靠:基于提供的引用和一般知识。 最后,添加引用标识:在相关段落末尾加[^1], [^2], [^3]。</think>### MyBatis 一级缓存和二级缓存的区别及使用方法 MyBatis 是一个流行的 Java 持久层框架,它通过缓存机制提升查询性能,减少数据库访问。缓存分为一级缓存和二级缓存,它们在范围、生命周期和配置方式上有所不同。下面我将逐步解释它们的区别及使用方法,确保内容清晰可靠。 #### 1. **一级缓存** - **定义**:一级缓存是 MyBatis 默认开启的缓存机制,作用于单个 `SqlSession` 级别(即一个数据库会话)。当在同一个 `SqlSession` 中执行相同的查询时,MyBatis 会直接从缓存中获取结果,避免重复查询数据库[^1]。 - **生命周期**:一级缓存在 `SqlSession` 开启时创建,关闭时自动清空。例如,如果执行 `session.close()`,缓存会失效。 - **特点**: - 默认启用,无需额外配置。 - 缓存范围仅限于当前会话,不同 `SqlSession` 之间隔离。 - 如果执行了增删改操作(如 `insert`、`update`、`delete`),MyBatis 会自动清空当前会话的一级缓存,以保证数据一致性[^2]。 - **使用方法**:一级缓存默认生效,无需代码干预。但可以通过配置调整其行为: - 在 MyBatis 配置文件中,设置 `localCacheScope` 属性: ```xml <settings> <setting name="localCacheScope" value="STATEMENT"/> <!-- 可选值:SESSION(默认)或 STATEMENT --> </settings> ``` - `value="SESSION"`:缓存作用于整个会话(默认)。 - `value="STATEMENT"`:缓存仅作用于单个语句,查询后立即清空(适合高并发场景)[^2]。 #### 2. **二级缓存** - **定义**:二级缓存是跨 `SqlSession` 的缓存机制,作用于 `SqlSessionFactory` 级别。它允许多个会话共享缓存数据,适合应用全局使用[^1]。 - **生命周期**:二级缓存的生命周期与 `SqlSessionFactory` 绑定,工厂关闭时清空。数据在会话提交(`commit()`)或关闭(`close()`)时新到二级缓存中。 - **特点**: - 需要显式开启,默认关闭。 - 支持跨会话共享数据,减少数据库压力。 - 缓存数据可序列化,但需注意线程安全和脏读问题(例如,多个会话修改同一数据时,需手动管理缓存失效)[^3]。 - **使用方法**: 1. **开启二级缓存**: - 在 MyBatis 配置文件(如 `mybatis-config.xml`)中添加设置: ```xml <settings> <setting name="cacheEnabled" value="true"/> <!-- 默认 true,但建议显式设置 --> </settings> ``` 2. **在 Mapper 文件中配置缓存**: - 在需要缓存的 Mapper XML 文件中添加 `<cache/>` 标签: ```xml <mapper namespace="com.example.UserMapper"> <cache eviction="LRU" flushInterval="60000" size="1024"/> <!-- 示例:LRU 策略,60秒新,容量1024个对象 --> </mapper> ``` - 常用属性: - `eviction`:缓存淘汰策略(如 LRU、FIFO)。 - `flushInterval`:自动新间隔(毫秒)。 - `size`:缓存对象数量上限。 3. **在代码中控制缓存**: - 查询时,确保使用 `commit()` 或 `close()` 来缓存: ```java SqlSession session = sqlSessionFactory.openSession(); User user = session.selectOne("getUserById", 1); // 结果会缓存到二级缓存 session.commit(); // 提交后数据新到二级缓存 session.close(); ``` - 如果不需要缓存某个查询,可在 SQL 映射中添加 `useCache="false"`: ```xml <select id="getUserById" resultType="User" useCache="false"> ... </select> ``` #### 3. **一级缓存和二级缓存的区别** | 特性 | 一级缓存 | 二级缓存 | |--------------|----------------------------------|----------------------------------| | **作用范围** | 单个 `SqlSession` 内部 | 跨多个 `SqlSession`(全局) | | **默认状态** | 默认开启 | 默认关闭,需显式配置 | | **生命周期** | 随 `SqlSession` 关闭而失效 | 随 `SqlSessionFactory` 关闭而失效 | | **数据共享** | 不同会话隔离,无共享 | 会话间共享数据 | | **性能影响** | 轻量级,减少单会话内重复查询 | 重量级,减少全局数据库访问 | | **适用场景** | 高频短会话操作(如单次请求) | 低频跨会话操作(如共享配置数据) | | **新机制** | 增删改操作自动清空当前缓存 | 需手动提交或关闭会话来新 | MyBatis 的缓存查询顺序是:先检查二级缓存,如果未命中再查一级缓存,最后查询数据库。数据库结果会先存入一级缓存,并在会话提交时同步到二级缓存[^3]。 #### 4. **使用建议** - **一级缓存**:适合大多数场景,无需额外管理。但在高并发事务中,建议设置 `localCacheScope=STATEMENT` 避免长会话占用内存[^2]。 - **二级缓存**: - 优点:显著提升性能,尤其对于读多写少的应用(如配置数据)。 - 缺点:需处理脏读(如使用 `<cache-ref>` 引用其他 Mapper 缓存以确保一致性)。 - 最佳实践:仅在需要时开启,避免缓存大型对象;定期监控缓存命中率。 - **通用原则**:优先使用一级缓存,二级缓存作为补充。测试时注意缓存对事务的影响。 通过合理配置,MyBatis 缓存能有效降低数据库负载,提升应用响应速度。如果遇到性能问题,可结合日志分析缓存命中情况[^1][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智慧浩海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值