MyBatis的缓存

  • 为什么使用缓存?

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

  • Mybatis中的一级缓存和二级缓存?

    • 一级缓存:

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

    • 二级缓存:

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

项目结构

User类

java 复制代码
public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String password;
    private String sex;
    private String address;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", password='" + password + '\'' +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                ", accountList=" + accountList +
                '}';
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    private List<Account> accountList;

    public List<Account> getAccountList() {
        return accountList;
    }

    public void setAccountList(List<Account> accountList) {
        this.accountList = accountList;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

}

一级缓存

一级缓存是SqlSession范围的缓存,当调用SqlSession的commit(),close()等方法时,就会清空一级缓存。

一级缓存结构图:

  1. 第一次发起查询用户id为 1 的用户信息,先去找缓存中是否有id为 1 的用户信息,如果没有,从数据库查询用户信息。 得到用户信息,将用户信息存储到一级缓存中。

  2. 如果sqlSession去执行 commit操作(执行插入、更新、删除),清空 SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读

  3. 第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。

在UserDao接口中

java 复制代码
public interface UserDao {
    //根据id查询用户信息
    public User findUserById(Integer id);
    void deleteUserById(Integer id);
}

在UserDao.xml文件中

java 复制代码
<?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.dao.UserDao">
    <select id="findUserById" resultType="User" parameterType="int">
        select * from user where id=#{id}
    </select>
</mapper>

在测试类

java 复制代码
public class MyBatisTset {
    private SqlSession sqlSession;
    private InputStream inputStream;
    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void init() throws IOException {
        //加载配置文件
        String resource = "mybatis-config.xml";
        inputStream = Resources.getResourceAsStream(resource);
        //创建SessionFactory
        sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
        //使用数据的会话实例
        sqlSession = sqlSessionFactory.openSession();
    }
    //一级缓存读取缓存sql(同一个sqlsession)
    @Test
    public void testGoCache1(){
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        System.out.println("================第一次查询================");
        User userById1 = userDao.findUserById(41);
        System.out.println(userById1);
        System.out.println("================第二次查询================");
        UserDao userDao2 = sqlSession.getMapper(UserDao.class);
        User userById2 = userDao2.findUserById(41);
        System.out.println(userById2);
    }
    //一级缓存不读取缓存sql(不同一个sqlsession)
    @Test
    public void testNoGoCache(){
        //SqlSession sqlSession = sessionFactory.openSession();
        SqlSession sqlSession1 =sqlSessionFactory.openSession();
        SqlSession sqlSession2 =sqlSessionFactory.openSession();
        //拥有不同的sqlsession
        UserDao UserDao1 = sqlSession1.getMapper(UserDao.class);
        UserDao UserDao2 = sqlSession2.getMapper(UserDao.class);
        System.out.println("================第一次查询================");
        User userById1 = UserDao1.findUserById(41);
        System.out.println(userById1);
        System.out.println("================第二次查询================");
        User userById2 = UserDao2.findUserById(41);
        System.out.println(userById2);
    }
//一级缓存不读取缓存sql(同一个sqlsession,执行CRUD操作)
    @Test
    public void testNoGoCache2(){
        //SqlSession sqlSession = sessionFactory.openSession();
        //拥有同一个sqlsession
        UserDao UserDao1 = sqlSession.getMapper(UserDao.class);
        UserDao UserDao2 = sqlSession.getMapper(UserDao.class);
        System.out.println("=============第一次查询============");
        User user1 = UserDao1.findUserById(41); //执行查询
        System.out.println(user1);
        System.out.println("=============两次查询之间执行增删改=============");
        UserDao1.deleteUserById(1);
        sqlSession.commit();
        System.out.println("=============第二次查询============");
        User user2 = UserDao2.findUserById(41);//执行查询
        System.out.println(user2);
    }

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

一级缓存读取缓存sql(同一个sqlsession)

一级缓存不读取缓存sql(不同一个sqlsession)

一级缓存不读取缓存sql(同一个sqlsession,执行CRUD操作)

二级缓存

二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

二级缓存结构图:

UserDao和UserDao.xml同上

测试类

java 复制代码
public class MybatisSecondCache {
        private SqlSession sqlSession;
        private InputStream inputStream;
        private SqlSessionFactory sqlSessionFactory;
        @Before
        public void init() throws IOException {
            //加载配置文件
            String resource = "mybatis-config.xml";
            inputStream = Resources.getResourceAsStream(resource);
            //创建SessionFactory
            sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
            //使用数据的会话实例
            sqlSession = sqlSessionFactory.openSession();
        }
        //二级缓存不执行sql
    @Test
    public void testGoCache(){
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        //拥有相同的sqlSessionFactrory
        UserDao UserDao1 = sqlSession1.getMapper(UserDao.class);
        UserDao UserDao2 = sqlSession2.getMapper(UserDao.class);

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

        System.out.println("=============第二次查询============");
        User user2 = UserDao2.findUserById(41);//执行sql?不执行sql
        System.out.println(user2);
    }
    //二级缓存执行sql(不同的sqlSessionFactrory)
    @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
        UserDao userMapper1 = sqlSession1.getMapper(UserDao.class);
        UserDao userMapper2 = sqlSession2.getMapper(UserDao.class);
        System.out.println("=============第一次查询============");
        User user1 = userMapper1.findUserById(41); //执行sql
        System.out.println(user1);
        sqlSession1.commit(); //第一次查询session执行commit或close,才会把数据写到二级缓存
        System.out.println("=============第二次查询============");
        User user2 = userMapper2.findUserById(41);//执行sql?执行sql
        System.out.println(user2);
    }
    //二级缓存执行sql(相同的sqlSessionFactrory)
    @Test
    public void testNoGoCache2(){
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        //拥有相同的sqlSessionFactrory
        UserDao userMapper1 = sqlSession1.getMapper(UserDao.class);
        UserDao userMapper2 = sqlSession2.getMapper(UserDao.class);
        System.out.println("=============第一次查询============");
        User user1 = userMapper1.findUserById(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.findUserById(41);//执行sql?执行sql
        System.out.println(user2);
    }
        @After
        public void close() throws IOException {
            sqlSession.close();
            inputStream.close();
        }
    }

二级缓存不执行sql

二级缓存执行sql(不同的sqlSessionFactrory)

二级缓存执行sql(相同的sqlSessionFactrory)

相关推荐
吾日三省吾码1 小时前
JVM 性能调优
java
弗拉唐2 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi773 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
少说多做3433 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀3 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
蓝黑20204 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea
Ysjt | 深4 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
凌冰_4 小时前
IDEA2023 SpringBoot整合MyBatis(三)
spring boot·后端·mybatis
shuangrenlong4 小时前
slice介绍slice查看器
java·ubuntu