高效作业之Mybatis缓存

高效作业之Mybatis缓存

  • 引言
  • [1. MyBatis的一级缓存](#1. MyBatis的一级缓存)
    • [1.1. 代码示例一级缓存](#1.1. 代码示例一级缓存)
    • [1.2. 使一级缓存失效的四种情况](#1.2. 使一级缓存失效的四种情况)
  • [2. Mybatis二级缓存](#2. Mybatis二级缓存)
    • [2.1. 代码示例二级缓存](#2.1. 代码示例二级缓存)
    • [2.2 使二级缓存失效的情况](#2.2 使二级缓存失效的情况)
    • [2.4. 二级缓存配置](#2.4. 二级缓存配置)
  • [3. MyBatis缓存查询的顺序](#3. MyBatis缓存查询的顺序)
  • [4. 整合第三方缓存EHCache](#4. 整合第三方缓存EHCache)
    • [4.1. 添加依赖](#4.1. 添加依赖)
    • [4.2. 创建EHCache的配置文件ehcache.xml](#4.2. 创建EHCache的配置文件ehcache.xml)
    • [4.3. 设置二级缓存的类型](#4.3. 设置二级缓存的类型)
    • [4.4. 加入logback日志](#4.4. 加入logback日志)

引言

Mybatis 缓存就是将查询出来的数据进行记录,等到下一次同样的条件进行查询的时候,就从缓存中取,Mybatis分为一级缓存和二级缓存,区别是范围不同,一级缓存是SqlSession级别的,二级缓存是SqlSessionFactory级别,接下来我们会结合代码和配置进行详细讲解。

1. MyBatis的一级缓存

一级缓存是SqlSession级别的,是默认的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问,缓存是为了提高查询速度的,接下来通过实际应用进行解说;

1.1. 代码示例一级缓存

1.新建立接口

缓存是针对查的缓存

java 复制代码
public interface CachMapper {
    User findById(int id);
}

2.建立CachMapper映射文件

bash 复制代码
<?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.mybatis.src.mapper.CachMapper">



    <select id="findById" parameterType="int" resultType="com.mybatis.src.User">
   select * from user where id =#{id};
   </select>
</mapper>
  1. 建立测试类
java 复制代码
package com.mybatis.src;

import com.mybatis.src.mapper.CachMapper;
import com.mybatis.src.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.Reader;

/**
 * @Description
 * @Date: $ $
 * $
 * $
 **/
public class CacheMapperTest {

    @Test
    public void CacheTest()
    {
        String resource="mybatis-config.xml";
        Reader reader=null;
        SqlSession sqlSession;
        try {
            reader= Resources.getResourceAsReader(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }

        SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader) ;
        sqlSession=sqlSessionFactory.openSession();
        //通过代理模式创建UserMapper接口的代理实现类对象
        CachMapper cachMapper = sqlSession.getMapper(CachMapper.class);
        User user1=cachMapper.findById(1);
        System.out.println(user1);
        User user2=cachMapper.findById(1);
        System.out.println(user2);
        sqlSession.close();
    }
}

可以看到我们2次session只输出了一个SQL语句,2个对象,这说明我们第二次查询是从缓存中读的。

在这个例子中我们用的是一个session,如果我们再新建一个session 那么会新生成SQL

java 复制代码
package com.mybatis.src;

import com.mybatis.src.mapper.CachMapper;
import com.mybatis.src.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.Reader;

/**
 * @Auther: lifang
 * @Description
 * @Date: $ $
 * $
 * $
 **/
public class CacheMapperTest {

    @Test
    public void CacheTest()
    {
        String resource="mybatis-config.xml";
        Reader reader=null;
        SqlSession sqlSession1;
        SqlSession sqlSession2;
        try {
            reader= Resources.getResourceAsReader(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }

        SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader) ;
        sqlSession1=sqlSessionFactory.openSession();
        sqlSession2=sqlSessionFactory.openSession();



        //通过代理模式创建UserMapper接口的代理实现类对象
        CachMapper cachMapper1 = sqlSession1.getMapper(CachMapper.class);
        CachMapper cachMapper2 = sqlSession2.getMapper(CachMapper.class);

        User user1=cachMapper1.findById(1);
        System.out.println(user1);
      //  User user2=cachMapper1.findById(1);
        User user2=cachMapper2.findById(1);
        System.out.println(user2);
        sqlSession1.close();
        sqlSession2.close();
    }
}

1.2. 使一级缓存失效的四种情况

  1. 不同的SqlSession对应不同的一级缓存
  2. 同一个SqlSession但是查询条件不同
  3. 同一个SqlSession两次查询期间执行了任何一次增删改操作
  4. 同一个SqlSession两次查询期间手动清空了缓存 sqlSession1.clearCache();

2. Mybatis二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取,二级缓存需要手动开启。

二级缓存开启的条件:

a>在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置

b>在映射文件中设置标签

c>二级缓存必须在SqlSession关闭或提交之后有效

d>查询的数据所转换的实体类类型必须实现序列化的接口,我们的实体类需要实现序列化类

java 复制代码
public class User implements Serializable {

2.1. 代码示例二级缓存

  1. 映射文件添加缓存标签
bash 复制代码
<?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.mybatis.src.mapper.CachMapper">

  <cache/>

    <select id="findById" parameterType="int" resultType="com.mybatis.src.User">
   select * from user where id =#{id};
   </select>
</mapper>

2.编写测试类

二级缓存是工程级别的因此需要生产2个session工厂

java 复制代码
public class CacheMapperTest {

    @Test
    public  void CacheTestTWO() {
        String resource = "mybatis-config.xml";
        Reader reader = null;

        try {
            reader = Resources.getResourceAsReader(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }

        SqlSessionFactory sqlSessionFactory1 = new SqlSessionFactoryBuilder().build(reader);

        SqlSession sqlSession1_1 = sqlSessionFactory1.openSession();

        Connection connection1 = sqlSession1_1.getConnection();
        try {
            connection1.setAutoCommit(true);
        } catch (SQLException e) {
            e.printStackTrace();


            CachMapper cachMapper1_1 = sqlSession1_1.getMapper(CachMapper.class);
            User user1 = cachMapper1_1.findById(1);
            sqlSession1_1.close();
            System.out.println(user1);


            SqlSession sqlSession1_2 = sqlSessionFactory1.openSession();
            Connection connection2 = sqlSession1_2.getConnection();
            try {
                connection2.setAutoCommit(true);
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            CachMapper cachMapper1_2 = sqlSession1_2.getMapper(CachMapper.class);
            User user2 = cachMapper1_2.findById(1);
            sqlSession1_2.close();
            System.out.println(user2);

        }
    }

2.2 使二级缓存失效的情况

两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效

2.4. 二级缓存配置

在mapper配置文件中添加的cache标签可以设置一些属性:

eviction属性:缓存回收策略

LRU(Least Recently Used) -- 最近最少使用的:移除最长时间不被使用的对象。

FIFO(First in First out) -- 先进先出:按对象进入缓存的顺序来移除它们。

SOFT -- 软引用:移除基于垃圾回收器状态和软引用规则的对象。

WEAK -- 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

默认的是 LRU。

flushInterval属性:刷新间隔,单位毫秒

默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新

size属性:引用数目,正整数

代表缓存最多可以存储多少个对象,太大容易导致内存溢出

readOnly属性:只读,true/false

true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了

很重要的性能优势。

false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是

false。

3. MyBatis缓存查询的顺序

先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。

如果二级缓存没有命中,再查询一级缓存

如果一级缓存也没有命中,则查询数据库

SqlSession关闭之后,一级缓存中的数据会写入二级缓存

4. 整合第三方缓存EHCache

4.1. 添加依赖

bash 复制代码
<!-- Mybatis EHCache整合包 -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
<!-- slf4j日志门面的一个具体实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>

4.2. 创建EHCache的配置文件ehcache.xml

bash 复制代码
<?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:\ehcache"/>
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>

4.3. 设置二级缓存的类型

bash 复制代码
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

4.4. 加入logback日志

存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。

创建logback的配置文件logback.xml

bash 复制代码
<?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.atguigu.crowd.mapper" level="DEBUG"/>
</configuration>
相关推荐
李慕婉学姐9 小时前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
奋进的芋圆11 小时前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
sxlishaobin11 小时前
设计模式之桥接模式
java·设计模式·桥接模式
model200511 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
荒诞硬汉11 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国12 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
2501_9418824812 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
華勳全栈12 小时前
两天开发完成智能体平台
java·spring·go
alonewolf_9912 小时前
Spring MVC重点功能底层源码深度解析
java·spring·mvc
沛沛老爹12 小时前
Java泛型擦除:原理、实践与应对策略
java·开发语言·人工智能·企业开发·发展趋势·技术原理