系列文章目录
Mybatis学习笔记Ⅰ
Mybatis学习笔记Ⅱ
一、Mybatis缓存
Mybatis 一级缓存的作用域是同一个 SqlSession,在同一个 sqlSession 中两次执行相同的 sql 语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个 sqlSession 结束后该 sqlSession 中的 一级缓存也就不存在了。Mybatis 默认开启一级缓存。
Mybatis 二级缓存是多个 SqlSession 共享的,其作用域是 mapper 的同一个 namespace,不同 的 sqlSession 两次执行相同 namespace 下的 sql 语句且向 sql 中传递参数也相同即最终执行 相同的 sql 语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从 缓存中获取数据将不再从数据库查询,从而提高查询效率。Mybatis 默认没有开启二级缓存 需要在 setting 全局参数中配置开启二级缓存。
二、一级缓存
测试一级缓存
测试1:
public void testFindDepartmentById1(){
SqlSession session = MybatisUtils.openSession();
DepartmentMapper departmentMapper = session.getMapper(DepartmentMapper.class);
//第一次查询
Department department1 = departmentMapper.findDepartmentById(1);
System.out.println(department1);
//第二次查询,由于是同一个session则不再向数据发出语句直接从缓存取出
Department department2 = departmentMapper.findDepartmentById(1);
System.out.println(department2);
session.close();
}
控制台日志打印(仅执行了一次sql语句):
测试2:
public void testFindDepartmentById2(){
SqlSession session = MybatisUtils.openSession();
DepartmentMapper departmentMapper = session.getMapper(DepartmentMapper.class);
//第一次查询
Department department1 = departmentMapper.findDepartmentById(20);
System.out.println(department1);
//在同一个session执行更新
Department departmentUpdate = new Department();
departmentUpdate.setDeptid(20);
departmentUpdate.setDeptname("Louis");
departmentUpdate.setDeptdesc("louis测试");
departmentUpdate.setDeptstate(0);
departmentMapper.updateDepartment(departmentUpdate);
session.commit();
//第二次查询,虽然是同一个session但是由于执行了更新操作session的缓存被 清空,这里重新发出sql操作
Department department2 = departmentMapper.findDepartmentById(20);
System.out.println(department2);
}
控制台日志打印(因更新操作执行了两次sql语句):
三、二级缓存
二级缓存区域是根据 mapper 的 namespace 划分的,相同 namespace 的 mapper 查询数据放 在同一个区域,如果使用 mapper 代理方法每个 mapper 的 namespace 都不同,此时可以理 解为二级缓存区域是根据 mapper 划分。 每次查询会先从缓存区域找,如果找不到从数据库查询,查询到数据将数据写入缓存。
1.配置开启二级缓存
①mybatis-config.xml加入设置
<settings>
<!--cacheEnabled:开启mybatis的二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
②Mapper映射文件中加入设置
<cache/>
③实现序列化
public class Department implements Serializable {}
2.测试二级缓存
public void testFindDepartmentById4(){
SqlSession session1 = MybatisUtils.openSession();
//使用session1执行第一次查询
DepartmentMapper departmentMapper1 = session1.getMapper(DepartmentMapper.class);
Department department1 = departmentMapper1.findDepartmentById(20);
System.out.println(department1);
session1.close();
SqlSession session2 = MybatisUtils.openSession();
//使用session2执行第二次查询,由于开启了二级缓存这里从缓存中获取数据不 再向数据库发出sql
DepartmentMapper departmentMapper2 = session2.getMapper(DepartmentMapper.class);
Department department2 = departmentMapper2.findDepartmentById(20);
System.out.println(department2);
System.out.println(department1==department2);
session2.close();
}
控制台日志打印(仅执行了一次sql语句):
四、缓存的类型
在进行缓存验证时,也想使用(department1 = department2 )
的布尔值进行判断
一级缓存:使用缓存为true
不使用缓存为false
二级缓存:是否使用缓存都为false
二级缓存并不是缓存的对象?
Mapper中可对cache进行配置readOnly属性
readOnly 为只读属性, 默认为 false
false: 可读写, 在创建对象时, 会通过反序列化得到缓存对象的拷贝。 因此在速度上会相对慢一点, 但重在安全。
true: 只读, 只读的缓存会给所有调用者返回缓存对象的相同实例。 因此性能很好, 但如果修改了对象, 有可能会导致程序出问题。
我使用的默认属性,缓存的是数据而不是对象,两次都是缓存对象的拷贝,所以比较结果为false。
参考文章:
https://blog.csdn.net/m0_53077601/article/details/122220305
https://blog.csdn.net/soulweee/article/details/120931839
总结
学习了Mybatis的缓存及机制。