MyBatis——第4章 查询缓存

本文深入探讨MyBatis的一级缓存和二级缓存机制,解析缓存的作用域、生命周期及工作原理。通过实例说明如何配置和使用二级缓存,包括内置二级缓存和ehcache二级缓存,以及增删改操作对缓存的影响。

根据作用域和生命周期分为两种:

一级缓存: 同一线程(SqlSession)间共享缓存,sqlSession一旦关闭,缓存将不复存在。

                   一级缓存只要用就有,一直处于开启状态。 

二级缓存: 不同线程间共享缓存(不同SqlSession 同一个namespace ),与整个应用生命周期是一致的

 

按照namespace划分,不同的互不干扰

4.1 一级缓存

证明一级缓存是存在的

		Student student = dao.selectStudentById(2);
		System.out.println(student);
		Student student2 = dao.selectStudentById(2);
		System.out.println(student2);

运行结果:只进行了一次查询,证明一级缓存是存在的

Mybatis:证明一级缓存中读取数据的依据是SQL id + SQL语句

Hibernate:缓存中读取数据的依据是查询结果对象id

ORM架构不同,查询依据不同

public interface IStudentDao {

	Student selectStudentById(int id);
	Student selectStudentById2(int id);
}

	public void test02(){
		Student student = dao.selectStudentById(2);
		System.out.println(student);
		Student student2 = dao.selectStudentById(2);
		System.out.println(student2);
	}



	<select id="selectStudentById" resultType="Student">
		select id,name,age,score
		from student 
		where id = #{id}
	</select>
	<select id="selectStudentById2" resultType="Student">
		select id,name,age,score
		from student 
		where id = #{id}
	</select>


查询依据肯定不是对象id

查询依据其实是SQL id和sql语句,缓存底层结构是个map,value是对象id(查询结果),key是SQL id和其对应的sql语句。

 

增删改操作会刷新一级缓存(清空一级缓存)

无论是否提交

	public void test03(){
		Student student = dao.selectStudentById(2);
		System.out.println(student);
		
		dao.insertStudent(new Student("赵六",25,93));
		
		Student student2 = dao.selectStudentById(2);
		System.out.println(student2);
	}

4.2 内置二级缓存

使用二级缓存的目的不是在多个查询中共享查询结果。而是为了防止同一查询(同SQL id 同SQL语句)的反复执行。

4.2.1 内置二级缓存的开启

 证明二级缓存是存在的

	//证明二级缓存是存在的
	@Test
	public void test01(){
		sqlSession = MyBatisUnils.getSqlSession();
		dao = sqlSession.getMapper(IStudentDao.class);
		Student student = dao.selectStudentById(2);
		System.out.println(student);
		
		sqlSession.close();
		
		sqlSession = MyBatisUnils.getSqlSession();
		dao = sqlSession.getMapper(IStudentDao.class);
		Student student2 = dao.selectStudentById(2);
		System.out.println(student2);
	}

① 对实体进行序列化,

② 在映射文件中添加cache标签  

 cache Hit Ratio 为命中率

增删改对二级缓存的影响

	public void test01(){
		sqlSession = MyBatisUnils.getSqlSession();
		dao = sqlSession.getMapper(IStudentDao.class);
		Student student = dao.selectStudentById(2);
		System.out.println(student);
		
		sqlSession.close();
		
		sqlSession = MyBatisUnils.getSqlSession();
		dao = sqlSession.getMapper(IStudentDao.class);
		dao.insertStudent(new Student("",0,0));
                Student student2 = dao.selectStudentById(2);
		System.out.println(student2);
	}
}

 

1.增删改同样会清空二级缓存

2.二级缓存的清空不是把<key,value>对都干掉,而是将key对应的value置为null,key仍然存在。

3.从DB中进行select查询的条件是:

    ① 缓存中根本就不存在这个key

    ② 缓存中存在key所对应的Entry对象,但是value为null

但不能对一级缓存进行配置

二级缓存的关闭

	<settings>
		<!--全局关闭二级缓存 -->
		<setting name="cacheEnabled" value="false"/>
	</settings>
<!--局部缓存关闭 -->
    <select id="selectStudentById"   useCache="false" resultType="Student">
		select id,name,age,score
		from student 
		where id = #{id}
	</select>

二级缓存的使用原则

① 多个namespace不操作同一张表

② 不要再关联关系表中做增删改操作

      一个接口对应一个对象的处理,一个mapper.xml文件对应一张表的处理

③ 查询多于修改时使用二级缓存

4.2.2 ehcache二级缓存

 

### MyBatis 第四 关联映射与缓存机制解析 #### 一、关联映射的核心概念 MyBatis 提供了强大的 `resultMap` 功能来支持复杂对象之间的关系映射。这种映射可以通过一对一、一对多以及多对多的关系实现数据表间的连接操作[^1]。具体来说: - **一对一映射**:适用于两个实体之间存在唯一对应关系的情况,例如订单和客户。 - **一对多映射**:用于描述一个父类拥有多个子类实例的情形,比如部门和员工。 - **多对多映射**:涉及中间表的场景下非常常见,例如学生选课。 为了完成上述映射,在 XML 文件中通常需要定义 `<association>` 或者 `<collection>` 节点,并指定外键字段作为条件进行匹配[^2]。 #### 二、缓存机制详解 MyBatis 支持两种类型的缓存——一级缓存和二级缓存。其中,一级缓存自动启用,而二级缓存则需显式配置才能生效。 ##### (1) 一级缓存概述 一级缓存的作用范围仅限于单个 SqlSession 实例内部。当同一个 SqlSession 中重复执行相同的 SQL 查询时,如果未发生任何修改,则可以直接返回之前的结果集而不重新访问数据库[^3]。 ##### (2) 二级缓存设计原理 相比之下,二级缓存覆盖整个 Mapper 层面,默认关闭状态。一旦激活之后,它允许不同线程间共享同一命名空间内的查询结果存储区。这意味着即使来自其他地方发起的新请求也可能利用已存在的高速缓冲副本而非再次调用底层物理磁盘读取动作[^2][^3]。 以下是启动二级缓存所需的几个关键步骤: 1. 修改全局 mybatis-config.xml 配置文件中的 settings 参数项,确保 cacheEnabled 设置为 true; 2. 在具体的 mapper xml 文档里加入 `<cache />` 声明节点或者通过 `<cache-ref namespace="otherMapperNamespace"/>` 方式引入外部定义好的公共缓存方案; 3. 可选项调整更多高级属性值如 eviction(驱逐算法), flushInterval(清理时间间隔秒数), size(最大条目数量限制),readOnly(true/false表示是否可序列化保存至硬盘文件系统上)[^3]。 下面给出一段简单的 Java 测试代码片段展示如何验证二级缓存效果: ```java // 创建第一个 session 并加载数据 try(SqlSession sqlSession = sqlSessionFactory.openSession()) { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); System.out.println(userMapper.getUserById(1)); // 输出第一次查得的对象信息 } // 创建第二个独立 session 尝试获取同样 id 数据 try(SqlSession anotherSqlSession = sqlSessionFactory.openSession()) { UserMapper userMapper = anotherSqlSession.getMapper(UserMapper.class); System.out.println(userMapper.getUserById(1)); // 此处应该直接命中二级缓存无需再发 db 请求 } ``` 注意以上例子假设已经正确设置了相关环境变量并且确认目标方法满足只读特性才可能观察到预期行为变化情况。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值