MyBatis 缓存

目录

一、缓存介绍

1、为什么使用缓存

2、Mybatis中的一级缓存和二级缓存

一级缓存

二级缓存

二、一级缓存

测试

总结

三、二级缓存

实现接口

开启二级缓存

[在SqlMapConfig.xml 文件开启二级缓存](#在SqlMapConfig.xml 文件开启二级缓存)

配置相关的Mapper映射文件

测试

总结


一、缓存介绍

1、为什么使用缓存

首次访问时,查询数据库,并将数据存储到内存中;再次访问时直接访问缓存,减少IO、硬盘读写次数、提高效率

2、Mybatis中的一级缓存和二级缓存
一级缓存

它指的是mybatis中的SqlSession对象的缓存。当我们执行完查询之后,查询的结果会同时存在在SqlSession为我们提供的一块区域中。当我们再次查询同样的数据,mybatis会先去SqlSession中查询是否有,有的话直接拿出来使用。当SqlSession对象消失时,Mybatis的一级缓存也就消失了。

二级缓存

它指的是Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessioFactory对象创建的SqlSession共享其缓存。

二、一级缓存

测试

UserMapper 接口

java 复制代码
public interface UserMapper {
    User getUserById(Integer id);

    void deleteUserById(Integer id);
}

UserMapper XML 映射文件

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.by.mapper.UserMapper">

    <select id="getUserById" parameterType="int" resultType="com.by.pojo.User">
        select * from user where id=#{id}
    </select>

  <delete id="deleteUserById" parameterType="int">
        delete from user where id=#{id}
    </delete>

</mapper>

测试类

java 复制代码
public class MyBatisFirstCacheTest {
    private SqlSession sqlSession;
    private InputStream inputStream;
    private SqlSessionFactory sessionFactory;

    @Before
    public void init() throws IOException {
        //加载mybatis-config.xml
        String resource = "mybatis-config.xml";
        inputStream = Resources.getResourceAsStream(resource);

        //创建sqlSessionFactory
        sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //创建sqlSession
        sqlSession = sessionFactory.openSession();
    }

    @Test
    public void testGoCache(){
        SqlSession sqlSession = sessionFactory.openSession();
        //拥有同一个sqlsession
        UserMapper userMapper1 = sqlSession.getMapper(UserMapper.class);
        UserMapper userMapper2 = sqlSession.getMapper(UserMapper.class);

        System.out.println("=============第一次查询============");
        User user1 = userMapper1.getUserById(41); //执行查询
        System.out.println(user1);

        System.out.println("=============第二次查询============");
        User user2 = userMapper2.getUserById(41);//执行查询?
        System.out.println(user2);
    }

    @Test
    public void testNoGoCache(){
        SqlSession sqlSession1 = sessionFactory.openSession();
        SqlSession sqlSession2 = sessionFactory.openSession();
        //拥有不同的sqlsession
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);

        System.out.println("=============第一次查询============");
        User user1 = userMapper1.getUserById(41); //执行查询
        System.out.println(user1);

        System.out.println("=============第二次查询============");
        User user2 = userMapper2.getUserById(41);//执行查询?不执行
        System.out.println(user2);
    }

    @Test
    public void testNoGoCache2(){
        SqlSession sqlSession = sessionFactory.openSession();
        //拥有同一个sqlsession
        UserMapper userMapper1 = sqlSession.getMapper(UserMapper.class);
        UserMapper userMapper2 = sqlSession.getMapper(UserMapper.class);

        System.out.println("=============第一次查询============");
        User user1 = userMapper1.getUserById(41); //执行查询
        System.out.println(user1);

        System.out.println("=============两次查询之间执行增删改=============");
        userMapper1.deleteUserById(1);
        sqlSession.commit();

        System.out.println("=============第二次查询============");
        User user2 = userMapper2.getUserById(41);//执行查询
        System.out.println(user2);
    }

    @After
    public void close() throws IOException {
       /* sqlSession.close();
        inputStream.close();*/
    }
}

testGoCache()

复制代码
Debug运行,可以看到是同一个sqlSession



testNoGoCache()
复制代码
testNoGoCache2()
总结

一级缓存范围是sqlSession,即在同一个会话的sqlSession中执行查询语句,查询结果已经被缓存,再次查询该语句时,不需要在执行查询语句,直接从缓存中读取即可

一级缓存是默认开启的

当使用不同sqlSession 或 两次查询之间执行了增删改操作时(MyBatis 会默认清空该会话的一级缓存,以确保缓存中的数据与数据库的状态保持一致,避免脏读),一级缓存就失效了,每次操作都需要执行查询语句

三、二级缓存

实现接口

注意:当我们在使用二级缓存时,所缓存的类一定要实现java.io.Serializable接口,这种就可以使用序列化方式来保存对象。

java 复制代码
public class User implements Serializable {

    private Integer id;
    private String username;
    private String password;
    private Date birthday;
    private String sex;
    private String address;
    //set get... ...
}    
开启二级缓存
在SqlMapConfig.xml 文件开启二级缓存
XML 复制代码
<settings>
    <!-- 开启二级缓存的支持 -->
    <setting name="cacheEnabled" value="true"/>
</settings>
配置相关的Mapper映射文件
XML 复制代码
<mapper namespace="com.by.dao.UserDao">
    <!-- 开启二级缓存的支持 -->
    <cache></cache>
测试

UserMapper 接口

java 复制代码
public interface UserMapper {
    User getUserById(Integer id);

    void deleteUserById(Integer id);
}

UserMapper XML 映射文件

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.by.mapper.UserMapper">
    <!--局部开启二级缓存-->
    <cache></cache>
    <select id="getUserById" parameterType="int" resultType="com.by.pojo.User">
        select * from user where id=#{id}
    </select>

    <delete id="deleteUserById" parameterType="int">
        delete from user where id=#{id}
    </delete>
</mapper>

测试类

java 复制代码
public class MyBatisSecondCacheTest {
    private SqlSession sqlSession;
    private InputStream inputStream;
    private SqlSessionFactory sessionFactory;

    @Before
    public void init() throws IOException {
        //加载mybatis-config.xml
        String resource = "mybatis-config.xml";
        inputStream = Resources.getResourceAsStream(resource);

        //创建sqlSessionFactory
        sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //创建sqlSession
        sqlSession = sessionFactory.openSession();
    }

    @Test
    public void testGoCache(){
        SqlSession sqlSession1 = sessionFactory.openSession();
        SqlSession sqlSession2 = sessionFactory.openSession();
        //拥有相同的sqlSessionFactrory
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);

        System.out.println("=============第一次查询============");
        User user1 = userMapper1.getUserById(41); //执行sql
        System.out.println(user1);
        sqlSession1.commit(); //第一次查询session执行commit或close,才会把数据写到二级缓存

        System.out.println("=============第二次查询============");
        User user2 = userMapper2.getUserById(41);//执行sql?不执行sql
        System.out.println(user2);
    }

    @Test
    public void testNoGoCache() throws IOException {
        //加载mybatis-config.xml
        String resource = "mybatis-config.xml";

        InputStream inputStream1 = Resources.getResourceAsStream(resource);
        SqlSessionFactory sessionFactory1 = new SqlSessionFactoryBuilder().build(inputStream1);

        InputStream inputStream2 = Resources.getResourceAsStream(resource);
        SqlSessionFactory sessionFactory2 = new SqlSessionFactoryBuilder().build(inputStream2);

        SqlSession sqlSession1 = sessionFactory1.openSession();
        SqlSession sqlSession2 = sessionFactory2.openSession();
        //拥有不相同的sqlSessionFactrory
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);

        System.out.println("=============第一次查询============");
        User user1 = userMapper1.getUserById(41); //执行sql
        System.out.println(user1);
        sqlSession1.commit(); //第一次查询session执行commit或close,才会把数据写到二级缓存

        System.out.println("=============第二次查询============");
        User user2 = userMapper2.getUserById(41);//执行sql?执行sql
        System.out.println(user2);
    }

    @Test
    public void testNoGoCache2(){
        SqlSession sqlSession1 = sessionFactory.openSession();
        SqlSession sqlSession2 = sessionFactory.openSession();
        //拥有相同的sqlSessionFactrory
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);

        System.out.println("=============第一次查询============");
        User user1 = userMapper1.getUserById(41); //执行sql
        System.out.println(user1);
        sqlSession1.commit(); //第一次查询session执行commit或close,才会把数据写到二级缓存


        System.out.println("=============两次查询之间执行增删改查=============");
        userMapper1.deleteUserById(1);
        sqlSession1.commit();

        System.out.println("=============第二次查询============");
        User user2 = userMapper2.getUserById(41);//执行sql?执行sql
        System.out.println(user2);
    }

    @After
    public void close() throws IOException {
       /* sqlSession.close();
        inputStream.close();*/
    }
}
复制代码
testGoCache()

testNoGoCache()

testNoGoCache2()

总结

二级缓存范围是sqlSessionFactory,即当开启二级缓存后,在一个应用中的不同 SqlSession 中执行相同的查询可以共享二级缓存,避免重复访问数据库。

二级缓存需要手动开启 <cache></cache>

当使用不同sqlSessionFactory 或 两次查询之间执行了增删改操作时(MyBatis 在默认情况下会在执行增删改操作时,清空对应的 SqlSessionFactory 的二级缓存。这是为了确保数据的一致性,避免脏读等问题),二级缓存就失效了,每次操作都需要执行查询语句。

相关推荐
她说彩礼65万2 小时前
C# AutoResetEvent和ManualResetEvent
java·jvm·c#
roman_日积跬步-终至千里2 小时前
【Docker多节点部署】基于“配置即身份“理念的 Docker 多节点 StarRocks 高可用集群自动化部署方案
java·docker·微服务
先知后行。3 小时前
C/C++八股文
java·开发语言
Yeats_Liao3 小时前
时序数据库系列(五):InfluxDB聚合函数与数据分析
java·后端·数据分析·时序数据库
又是忙碌的一天4 小时前
Java IO流
java·开发语言
程序员buddha4 小时前
springboot-mvc项目示例代码
java·spring boot·mvc
不懂英语的程序猿5 小时前
【Java 工具类】Java通过 TCP/IP 调用斑马打印机(完整实现)
java
多多*6 小时前
分布式系统中的CAP理论和BASE理论
java·数据结构·算法·log4j·maven
sg_knight6 小时前
Docker 实战:如何限制容器的内存使用大小
java·spring boot·spring·spring cloud·docker·容器·eureka
合作小小程序员小小店7 小时前
web网页开发,在线考勤管理系统,基于Idea,html,css,vue,java,springboot,mysql
java·前端·vue.js·后端·intellij-idea·springboot