mybatis缓存
缓存的概念:缓存就是数据交互的缓冲区“Cache”。就是计算机已经接受并使用过一次,然后保存下来以便于将来使用的数据。在mybatis中的缓存可分为两级,对于已从同一个SqlSession获取的数据,第二次查询相同的数据时不会再访问数据库(mybatis一级缓存默认开启)。但需要注意的是无论是一级还是二级缓存每次“增删改”操作都会清空缓存。
1、一级缓存:一级缓存是默认开启的。一级缓存是在会话(SqlSession)层面实现的,这就说明一级缓存作用范围只能在同一个SqlSession中,跨SqlSession是无效的。手动清空一级缓存的函数SqlSession.clearCache()。
接口文件:
package com.ssm.mybatis.mapper;
import com.ssm.mybatis.pojo.Emp;
import org.apache.ibatis.annotations.Param;
/**
* @Author: 黎金成
* @Description: TODO
* @DateTime: 2022/9/17 9:53
**/
public interface CacheMapper {
Emp getEmpById(@Param("empId") Integer empId);
}
xml文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ssm.mybatis.mapper.CacheMapper">
<!-- Emp getEmpById(@Param("empId") Integer empId);-->
<select id="getEmpById" resultType="Emp">
select * from t_emp where emp_id = #{empId}
</select>
</mapper>
test测试类:
package com.ssm.mybatis.test;
import com.ssm.mybatis.mapper.CacheMapper;
import com.ssm.mybatis.pojo.Emp;
import com.ssm.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
/**
* @Author: 黎金成
* @Description: TODO
* @DateTime: 2022/9/17 11:19
**/
public class CacheTest {
@Test
public void getEmpByIdCache(){
SqlSession sqlSession = SqlSessionUtil.getSqlSeeion();
CacheMapper mapper = sqlSession.getMapper(CacheMapper.class);
Emp emp = mapper.getEmpById(1);
System.out.println(emp);
Emp emp2 = mapper.getEmpById(1);
System.out.println(emp2);
}
}
执行结果:可以看到这里有两条输出语句,但只执行了一个sql。可知第二次输出的emp2并不是从数据中查询得来而是从缓存中获取。
不同SqlSession查询相同一条数据,和同一个SqlSession查询不同的数据,一级缓存都会失效。
test测试类:
package com.ssm.mybatis.test;
import com.ssm.mybatis.mapper.CacheMapper;
import com.ssm.mybatis.pojo.Emp;
import com.ssm.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
/**
* @Author: 黎金成
* @Description: TODO
* @DateTime: 2022/9/17 11:19
**/
public class CacheTest {
@Test
public void getEmpByIdCache(){
SqlSession sqlSession = SqlSessionUtil.getSqlSeeion();
CacheMapper mapper = sqlSession.getMapper(CacheMapper.class);
SqlSession sqlSession2 = SqlSessionUtil.getSqlSeeion();
CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
Emp emp = mapper.getEmpById(1);
System.out.println(emp.hashCode()+""+emp);
Emp emp2 = mapper.getEmpById(2);
System.out.println(emp2.hashCode()+""+emp2);
Emp emp3 = mapper2.getEmpById(1);
System.out.println(emp3.hashCode()+""+emp3);
}
}
运行结果:不同的hashCode表明这是三个不同的对象,同一个对象在内存里只有一个。
2、二级缓存:二级缓存属于namespace级别,(即同一个sqlSessionFactory获取的SqlSession对象),默认不开启,开启二级缓存有四个条件,开始方式如下。(二级缓存有命中率)
开启方式:
(1)、在核心配置文件mybatis-config.xml中添加如下配置:(默认值为true,故此配置不需要再手动添加)
<setting name="cacheEnabled" value="true"/>
(2)、在映射文件中添加标签
(3)、当前操作完成后用SqlSession.close()方法关闭SqlSession,当SqlSession关闭后保存在其中的一级缓存的数据将会提交至二级缓存进行保存。
SqlSession.close();
(4)、查询的数据所转换的实体类类型必须实现序列化的接口。如这里使用的Emp实体类。
测试二级缓存:
test方法:
public void testCache() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(resourceAsStream);
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
Emp emp1 = mapper1.getEmpById(1);
System.out.println(emp1);
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
Emp emp2 = mapper2.getEmpById(1);
System.out.println(emp2);
}
执行结果:
二级缓存的管理:二级缓存的管理通过在核心配置文件mybatis-config.xml中添加标签实现,该标签有type、flushInterval、size、readOnly、eviction六个属性。
属性 | 作用 | 配置 |
---|---|---|
eviction | 缓存策略 | LRU(最近最少使用,没错就是操作系统那个LRU算法),默认是LRU。FIFO(先进先出算法)。SOFT( 软引用)。WEAK( 弱引用)。 |
flushInterval | 刷新间隔 | 根据具体配置 |
size | 引用数目 | 根据具体配置 |
readOnly | 只读 | true/false(默认是false)。设置为true时会返回和缓存对象的只读的相同实例。无法对返回的对象进行修改操作。false是读写缓存,将在内存中的对象进行拷贝,再将拷贝后的对象返回给调用者。这会慢一点,但是更安全。 |
3、整合第三方缓存:整合第三方缓存是针对于二级缓存的。
使用:
(1)、创建EHCache的配置文件。(具体配置项可查看相关资料)
<?xml version="1.0" encoding="utf-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- 磁盘保存路径 -->
<diskStore path="D:\Java\dataEHCache"/>
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
(2)、在接口配置文件CacheMapper.xml中添加如下配置。
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
注意:当使用slf4j日志时,作为普通日志的log4j将失效,因此需要开启slf4j的logback来打印日志。logback的使用分为以下两个步骤。
(1)、创建logback.xml文件
在这里插入代码片<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<!-- 指定日志输出的位置 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 日志输出的格式 -->
<!-- 按照顺序分别是: 时间、日志级别、线程名称、打印日志的类、日志主体内容、换行
-->
<pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger]
[%msg]%n</pattern>
</encoder>
</appender>
<!-- 设置全局日志级别。日志级别按顺序分别是: DEBUG、INFO、WARN、ERROR -->
<!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
<root level="DEBUG">
<!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
<appender-ref ref="STDOUT" />
</root>
<!-- 根据特殊需求指定局部日志级别 -->
<logger name="com.ssm.mybatis.mapper" level="DEBUG"/>
</configuration>