MyBatis缓存机制
在 MyBatis 中允许使用缓存,缓存一般都放置在可高速读/写的存储器上,比如服务器的内存,它能够有效提高系统的性能。数据库在大部分场景下从磁盘上的索引数据,从硬件的角度分析,索引磁盘是一个较为缓慢的过程,读取内存或者高速缓存处理器的速度是读取磁盘速度的几十倍到上百倍,但是内存和高速缓存处理器的空间有限,所以一般只会把那些常用且命中率高的数据缓存起来,以便将来使用,而不缓存那些不常用或命中率低的数据,这些数据最后还是要在磁盘内查找,并不能有效提高性能。
MyBatis 分为一级缓存和二级缓存,也可以配置关于缓存的设置。
- 和大多数持久层框架类似,MyBatis同样提供了2 级缓存: session 和namespace
- 当session调用clearCache、close方 法时,则其中的缓存数据会清空
- 当执行C/U/D操作时,默认情况下,相应作用域的缓存也会被清空
一级缓存和二级缓存
一级缓存是在 SqISession 上的缓存,二级缓存是在 SqISessionFactory上的缓存。在默认情况下,也就是在没有任何配置的情况下,MyBatis 系统会开启一级缓存,这个缓存不需要POJO对象可序列化(实现 java.jo.Serializable 接口)。
一级缓存
一级缓存特点:
-
一级缓存,默认存在,无法关闭
-
缓存的数据存储在SQLSession对象中(类似Map集合,键对应的sql语句,值就是语句对应的结果)
一级缓存如何保证数据一致性的:
-
当执行查询语句时,自动走缓存,缓存中如果有数据就返回,缓存没有就查询数据库,更新缓存
-
当执行非查询语句时(新增、修改、删除),就会自动删除缓存
接下来通过代码演示来验证缓存的存在
在验证之前先了解下Mybatis的日志如何配置,通过日志我们可以在控制台看到sql语句的打印信息
Mybatis内置的有日志记录,但是需要配置才会生效
日志配置步骤:
导入依赖jar
<!-- 日志处理 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
在mybatis-config.xml中开启日志
<settings>
<!-- 开启日志 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
通过代码演示来验证缓存的存在
-
创建mapper接口(编写操作数据库的各种方法)
public interface PhoneDao { /** * 新增*/ int add(Phone phone); /** * 查询*/ List<Phone> selectAll(); }
-
创建mapper接口对应的映射文件(编写方法对应的sql语句)
<!-- 命名空间 唯一 写上对应接口名的全称--> <mapper namespace="com.feri.mybatis.dao.PhoneDao"> <insert id="add" useGeneratedKeys="true" keyProperty="id"> insert into t_phone(name,brand,model,price,ctime) values(#{name},#{brand},#{model},#{price},now()) </insert> <select id="selectAll" resultType="com.feri.mybatis.entity.Phone"> select * from t_phone </select> </mapper>
-
在mybatis.xml中注册mapper映射文件
-
测试
@Test
public void t1() throws IOException {
//1.创建工厂对象
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(
Resources.getResourceAsStream("mybatis-config.xml"));
//2.获取 会话对象
SqlSession session=factory.openSession(true);
//3.获取接口的实现类对象
PhoneDao dao=session.getMapper(PhoneDao.class);
System.err.println("新增:"+dao.add(new Phone("苹果14Pro","苹果","14",8999.0)));
System.err.println("查询:"+dao.selectAll());
}
二级缓存
二级缓存特点
-
二级缓存是把缓存的数据存储在SQLSessionFactory上面(对象内部)
-
二级缓存的数据,所有的session可以共用
-
二级缓存默认关闭,使用的需要配置
二级缓存实现步骤:
-
把要缓存的对象对应的类实现序列化接口
@Data @NoArgsConstructor public class Phone implements Serializable { private Integer id; private String name; private String brand; private String model; private Double price; private Date ctime; public Phone(String name, String brand, String model, Double price) { this.name = name; this.brand = brand; this.model = model; this.price = price; } }
-
在mybatis-config中开启二级缓存
<settings> <!-- 开启日志--> <setting name="logImpl" value="STDOUT_LOGGING"/> <!-- 开启二级缓存--> <setting name="cacheEnabled" value="true"/> </settings>
-
在需要使用二级缓存的映射文件中实现配置
<!-- 二级缓存设置 cache 二级缓存 size属性:容量 eviction:策略,容量满的时候,改按照什么规则删除缓存数据 常用:1.LRU(最近最少使用原则) 2.FIFO(先进先出) 3.Soft(软引用) 4.Weak(弱引用) --> <cache size="1024" eviction="LRU"></cache>
-
编写代码测试二级缓存
@Test public void t4() throws IOException { //1.创建工厂对象 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build( Resources.getResourceAsStream("mybatis-config.xml")); //2.获取 会话对象 SqlSession session1 = factory.openSession(true); SqlSession session2 = factory.openSession(true); //3.验证二级缓存 System.err.println("第一个会话:"+session1.getMapper(PhoneDao.class).selectAll()); session1.close(); System.err.println("第二个会话:"+session2.getMapper(PhoneDao.class).selectAll()); }