美文网首页
mybatis一级缓存失效的四种情况

mybatis一级缓存失效的四种情况

作者: 捞月亮的阿汤哥 | 来源:发表于2019-06-12 21:31 被阅读0次

什么是mybatis的一级缓存

mybatis的一级缓存是基于sqlsession的缓存,默认开启,如果会话失效,则缓存失效。

mybatis一级缓存失效的四种情况

  • sqlsession变了 缓存失效
  • sqlsession不变,查询条件不同,一级缓存失效
  • sqlsession不变,中间发生了增删改操作,一级缓存失败
  • sqlsession不变,手动清除缓存,一级缓存失败

mybatis一级缓存失败的实验

1. 创建部门表

create table if not exists tbl_dept
(
    dept_id int not null
        primary key,
    dept_name varchar(32) null
);

2. 修改mybatis-config.xml的配置文件

为了更好的看到sql的执行情况,我们这边需要配置log4j,并添加log4j的jar包到项目路径

<settings>
        <!--        指定mybatis的日志-->
      <setting name="logImpl" value="LOG4J"/>
</settings>

修改log4j.properties

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <param name="Encoding" value="UTF-8"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) \n"/>
        </layout>
    </appender>
    <logger name="java.sql">
        <level value="debug"/>
    </logger>
    <logger name="org.apache.ibatis">
        <level value="info"/>
    </logger>
    <root>
        <level value="debug"/>
        <appender-ref ref="STDOUT"/>
    </root>
</log4j:configuration>

3. 编写对应的mapper接口和xml文件

DeptMapper.java文件如下:

public interface DeptMapper {
    Department findDepartmentById(Integer deptId);

    void insertDepartment(Department department);
}

DeptMapper.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.zihao.mapper.DeptMapper">
    <select id="findDepartmentById" resultType="com.zihao.model.Department">
        select dept_id, dept_name
        from tbl_dept
        where dept_id = #{deptId}
    </select>

    <insert id="insertDepartment">
        insert into tbl_dept(dept_id, dept_name)
        values (#{deptId},#{deptName})
    </insert>
</mapper>

4. 测试代码

package com.zihao.test;

import com.zihao.mapper.DeptMapper;
import com.zihao.model.Department;
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 java.io.IOException;
import java.io.InputStream;

public class FirstCacheTest {

    /**
     * 两次查出来的dept对象一样,而且sql只有一条,意味着使用了一级缓存
     * 一直开启, 基于sqlsession的一级缓存
     * 1) sqlsession变了 缓存失效
     * 2) sqlsession不变,查询条件不同,一级缓存失效
     * 3) sqlsession不变,中间发生了增删改操作,一级缓存失败
     * 4) sqlsession不变,手动清除缓存,一级缓存失败
     */

    /**
     *  两次查出来的dept对象一样,而且sql只有一条,意味着使用了一级缓存
     *  一级缓存一直开启, 基于sqlsession的一级缓存
     * @throws IOException
     */
    public static void testFirstCacheSuccessful() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //3. 关联mapper文件
        try {
            DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
            Department department = deptMapper.findDepartmentById(1);

            System.out.println(department);

            Department departmentCached = deptMapper.findDepartmentById(1);
            System.out.println(department == departmentCached);

        } finally {
            //4. 关闭连接
            sqlSession.close();
        }
    }

    /**
     * 第一种缓存失效的情况,sqlsession发生了变化
     */
    public static void testFirstCacheFailedCase1() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. SqlSession
        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
        SqlSession sqlSession2 = sqlSessionFactory.openSession(true);

        //3. 关联mapper文件
        try {
            DeptMapper deptMapper1 = sqlSession1.getMapper(DeptMapper.class);
            Department department1 = deptMapper1.findDepartmentById(1);


            DeptMapper deptMapper2 = sqlSession2.getMapper(DeptMapper.class);
            Department department2 = deptMapper2.findDepartmentById(1);

            //false
            System.out.println(department1==department2);

        } finally {
            //4. 关闭连接
            sqlSession1.close();
            sqlSession2.close();
        }
    }

    /**
     * 第二种缓存失效的情况,同一个sqlsession,但是查询条件发生了变化
     */
    public static void testFirstCacheFailedCase2() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //3. 关联mapper文件
        try {
            DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
            Department department1 = deptMapper.findDepartmentById(1);

            Department department2 = deptMapper.findDepartmentById(2);

            //false
            System.out.println(department1==department2);

        } finally {
            //4. 关闭连接
            sqlSession.close();
        }
    }

    /**
     * 第三种缓存失效的情况,同一sqlsession,但是中间发生了增删改的操作
     */
    public static void testFirstCacheFailedCase3() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. SqlSession
        // 这边无论是否是自动提交,结果都是false
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //3. 关联mapper文件
        try {
            DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
            Department department1 = deptMapper.findDepartmentById(1);



            Department departmentAdded = new Department();
            departmentAdded.setDeptId(6);
            departmentAdded.setDeptName("战略规划部");
            deptMapper.insertDepartment(departmentAdded);


            Department department2 = deptMapper.findDepartmentById(1);

            //false
            System.out.println(department1==department2);

        } finally {
            //4. 关闭连接
            sqlSession.close();
        }
    }

    /**
     * 第四种缓存失效的情况,同一sqlsession,但是手动清了缓存
     */
    public static void testFirstCacheFailedCase4() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. SqlSession
        // 这边无论是否是自动提交,结果都是false
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //3. 关联mapper文件
        try {
            DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
            Department department1 = deptMapper.findDepartmentById(1);

            //手动清空缓存
            sqlSession.clearCache();

            Department department2 = deptMapper.findDepartmentById(1);

            //false
            System.out.println(department1==department2);

        } finally {
            //4. 关闭连接
            sqlSession.close();
        }
    }


    public static void main(String[] args) throws IOException {
        //testFirstCacheSuccessful(); //true
        //testFirstCacheFailedCase1(); //false
        //testFirstCacheFailedCase2(); //false
        //testFirstCacheFailedCase3(); //false
        testFirstCacheFailedCase4(); //false
    }
}

5. 相关说明

  • 如何判断缓存有没失效?
    可以通过比较两次查询的对象是否相等,或者查看控制台的日志,比如下面的
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
Wed Jun 12 21:10:53 CST 2019 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
DEBUG 06-12 21:10:53,552 ==>  Preparing: select dept_id, dept_name from tbl_dept where dept_id = ?   (BaseJdbcLogger.java:159) 
DEBUG 06-12 21:10:53,579 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:159) 
DEBUG 06-12 21:10:53,604 <==      Total: 1  (BaseJdbcLogger.java:159) 
DEBUG 06-12 21:10:53,605 ==>  Preparing: select dept_id, dept_name from tbl_dept where dept_id = ?   (BaseJdbcLogger.java:159) 
DEBUG 06-12 21:10:53,606 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:159) 
DEBUG 06-12 21:10:53,607 <==      Total: 1  (BaseJdbcLogger.java:159) 

可以清晰的看到,mybatis发送了两次请求

  • 针对上文的第三种情况,即中间发生了增删改操作,我这边只是试验了增加操作。对于插入操作,我这边显示声明了自动提交,如果自动提交设置成false的话,结果还是一级缓存失效的。原因是因为insert标签的flushCache属性默认是true,所以一级缓存失效
  • 一级缓存如何关闭呢,请看下面一篇文章。

6. 其他

mybatis开发推荐下Mybatis plugin,虽然有点贵,但是补全和提示做的挺好的,而且可以一直更新。

相关文章

  • mybatis一级缓存失效的四种情况

    什么是mybatis的一级缓存 mybatis的一级缓存是基于sqlsession的缓存,默认开启,如果会话失效,...

  • mybaits一级缓存失效

    mybatis+spring环境下缓存的使用和mybatis一级缓存失效原因 - CSDN博客

  • Mybatis缓存

    mybatis分为一级缓存和二级缓存,在默认的情况下,Mybatis只会开启一级缓存 一级缓存 一级缓存是一次会话...

  • Mybatis缓存介绍

    Mybatis介绍之缓存 Mybatis中有一级缓存和二级缓存,默认情况下一级缓存是开启的,而且是不能关闭的。一级...

  • mybatis一级缓存和二级缓存

    MyBatis官网MyBatis拥有自带一级缓存和二级缓存 一级缓存: MyBatis是默认开启一级缓存,一级缓存...

  • MyBatis缓存书目录

    MyBatis缓存 MyBatis介绍 MyBatis一级缓存 1、什么是一级缓存? 为什么使用一级缓存? 2、M...

  • mybatis一级缓存和二级缓存

    mybatis的一级缓存 Mybatis在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlS...

  • 你真的懂Mybatis缓存机制吗

    MyBatis自带的缓存有一级缓存和二级缓存。 一级缓存 Mybatis的一级缓存是指Session缓存。一级缓存...

  • java基础面试题总结——其他大型框架

    1. 简述mybatis缓存机制的实现原理 mybatis缓存分为一级缓存和二级缓存: 一级缓存 概念:一级缓存即...

  • Mybatis 缓存机制

    Mybatis 中有一级缓存和二级缓存,默认情况下一级缓存是开启的,而且是不能关闭的。一级缓存是指SqlSessi...

网友评论

      本文标题:mybatis一级缓存失效的四种情况

      本文链接:https://www.haomeiwen.com/subject/dywrfctx.html