MyBatis笔记Day04_Mybatis_c02Cache缓存

1、缓存概述:

    存在于内存中的临时数据。
使用缓存的目的:
    减少与数据库的交互次数,提高查询速度。
什么数据适用缓存,什么数据不适用缓存:
    适用:经常要查询并且不经常改变的,数据正确性对最终结果影响不大的。
    不适用:经常改变的数据,数据正确性对结果影响很大的。

2、Mybatis中的缓存:

一级缓存

    Mybatis中sqlSession对象的缓存,当执行查询时,Mybatis会先将结果以Map和形式存放,当再次查询相同数据时,会先从Map中获取。要注意的是当sqlSession对象消失时,一级缓存也就与之一同消失。
下面,我们对一级缓存进行测试。

package cn.snowing.test;

import cn.snowing.dao.IUserDao;
import cn.snowing.domain.User;
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.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class UserTest {
    private InputStream in;
    SqlSessionFactory factory;
    private SqlSession sqlSession;
    private IUserDao userDao;

    @Before
    public void init() throws IOException {
        //1.获取主配置文件输入流
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.获取SqlSessionFactory工厂
        factory = new SqlSessionFactoryBuilder().build(in);
        //3.获取SqlSession对象
        sqlSession = factory.openSession();
        //4.获取Dao的代理对象
        userDao = sqlSession.getMapper(IUserDao.class);
    }

    @After
    public void destroy() throws IOException {
        //提交事务
        sqlSession.commit();
        //6.释放资源
        sqlSession.close();
        in.close();
    }

    /**
     * 测试一级缓存,当sqlSession消失时,一级缓存也消失了,当调用删除、更新、commit、close时会清空一级缓存
     */
    @Test
    public void testFirstLevelCache(){
        User user1 = userDao.findUserById(41);
        User user2 = userDao.findUserById(41);
        System.out.println(user1);
        System.out.println(user2);
        System.out.println(user1 == user2);
    }

}

    在测试代码中,可以看到,我们对id为41的用户进行了再次查询,然后分别赋值给user1,user1通过打印两个对象的引入,以及==判断,我们发现user1和user2的完全相等的两个对象。
在这里插入图片描述
    前面有提到,当sqlSession对象消失时,一级缓存也就消失了,我们对这一点进行测试。首先进行第一次查询,然后将sqlSession对象关闭,再重新使用其工厂新建一个sqlSession,最后再进行查询。通过结果我们可以发现与上面的不同,这里查询到的两个个对象是不相同的,这就说明了在sqlSession关闭之后一级缓存就会消失。

@Test
    public void testFirstLevelCache(){
        User user1 = userDao.findUserById(41);
        sqlSession.close();
        sqlSession = factory.openSession();
        userDao = sqlSession.getMapper(IUserDao.class);
        User user2 = userDao.findUserById(41);
        System.out.println(user1);
        System.out.println(user2);
        System.out.println(user1 == user2);
    }

在这里插入图片描述
    sqlSession其实提供了消除缓存的方法clearCache(),调用该方法,同样可以对一级缓存进行清除。此外,当调用删除、更新、commit、close时会清空一级缓存。

二级缓存

Mybatis中sqlSessionFactory对象的缓存,由同一个sqlSessionFactory对象创建的sqlSession对象共享其缓存。
二级缓存的使用步骤:
1). 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。(在主配置文件中配置)根据官方文档的说明,这个是默认开启的。

    <settings>
        <setting name="cacheEnabled" value="true"/>
    settings>

2). 开启当前映射文件的二级缓存(在IUserDao.xml中配置)

<mapper namespace="cn.snowing.dao.IUserDao">
    
    <cache/>
     
mapper>

3). 开启当前操作的二级缓存(在select标签的useCache属性中配置)

<select id="findUserById" resultType="cn.snowing.domain.User" parameterType="Integer" useCache="true">
    select * from user where id = #{id}
select>

经过上面的配置,二级缓存配置成功。下面,我们对其进行测试。

package cn.snowing.test;

import cn.snowing.dao.IUserDao;
import cn.snowing.domain.User;
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.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class SecondLevelCacheTest {
    private InputStream in;
    SqlSessionFactory factory;

    @Before
    public void init() throws IOException {
        //1.获取主配置文件输入流
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.获取SqlSessionFactory工厂
        factory = new SqlSessionFactoryBuilder().build(in);
    }

    @After
    public void destroy() throws IOException {
        in.close();
    }

    /**
     * 测试一级缓存,当sqlSession消失时,一级缓存也消失了,当调用删除、更新、commit、close时会清空一级缓存
     */
    @Test
    public void testSecondLevelCache(){
        SqlSession sqlSession1 = factory.openSession();
        IUserDao dao1 = sqlSession1.getMapper(IUserDao.class);
        User user1 = dao1.findUserById(41);
        System.out.println(user1);
        sqlSession1.close();

        SqlSession sqlSession2 = factory.openSession();
        IUserDao dao2 = sqlSession2.getMapper(IUserDao.class);
        User user2 = dao2.findUserById(41);
        sqlSession2.close();
        System.out.println(user2);

        System.out.println(user1 == user2);
    }

}

没有配置之前的结果
MyBatis笔记Day04_Mybatis_c02Cache缓存_第1张图片
配置之后的结果
MyBatis笔记Day04_Mybatis_c02Cache缓存_第2张图片

可以看到,没有配置之前,其对数据库进行了两次查询,而配置之后只进行了一次查询。但是问题是这两个对象为什么是不相等的呢?其原因是Mybatis的二级缓存不同于一级缓存,一级缓存存的是对象,而二级缓存存放的则是数据。也就是说在查找到二级缓存时,Mybatis则数据封装到了一个新的对象里面。因此,再次查询得到的对象是不相同的。

你可能感兴趣的:(mybatis)