mybatis缓存机制

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并不是从数据中查询得来而是从缓存中获取。
可以看到这里有两条输出语句,但只执行了一个sql。
不同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>

4、缓存的查询策略:首先查询二级缓存,如二级缓存未命中则查询一级缓存,若一级缓存也没有则查询数据库。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值