MyBatis 缓存

发布时间:2023年12月25日

目录

一、缓存介绍

1、为什么使用缓存

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

一级缓存

二级缓存

二、一级缓存

测试

总结

三、二级缓存

实现接口

开启二级缓存

在SqlMapConfig.xml 文件开启二级缓存

配置相关的Mapper映射文件

测试

总结


一、缓存介绍

1、为什么使用缓存

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

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

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

二级缓存

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

二、一级缓存

测试

UserMapper 接口

public interface UserMapper {
    User getUserById(Integer id);

    void deleteUserById(Integer id);
}

UserMapper ?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>

测试类

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接口,这种就可以使用序列化方式来保存对象。

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 文件开启二级缓存
<settings>
    <!-- 开启二级缓存的支持 -->
    <setting name="cacheEnabled" value="true"/>
</settings>
配置相关的Mapper映射文件
<mapper namespace="com.by.dao.UserDao">
    <!-- 开启二级缓存的支持 -->
    <cache></cache>
测试

UserMapper 接口

public interface UserMapper {
    User getUserById(Integer id);

    void deleteUserById(Integer id);
}

UserMapper ?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>

测试类

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 的二级缓存。这是为了确保数据的一致性,避免脏读等问题),二级缓存就失效了,每次操作都需要执行查询语句。

文章来源:https://blog.csdn.net/qq_57570052/article/details/135193419
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。