Mybatis入门笔记(11)——Mybatis的缓存

Mybatis的缓存

缓存基本概念

缓存是存在于内存中的临时数据

为什么用缓存?减少和数据库的交互次数,提高执行效率。

什么地方用缓存?

条件 情况
适用于缓存 经常查询并且不经常改变的,数据的正确与否对最终结果影响不大的
不适用于缓存 经常改变的数据,数据的正确性与否对最终结果影响很大的,比如:商品的库存,银行的汇率,股市的牌价等。

一级缓存

一级缓存指的是Mybatis中SqlSession对象的缓存。当我们执行查询后,查询的结构会同时存入到SqlSession为我们提供的一块区域中,该区域的结构是一个Map,当我们再次查询同样的数据,Mybatis会先去SQLSession中查询是否有,有的话直接拿出来用。当SQLSession对象消失后(被flush或close),Mybatis的一级缓存也就消失了。

下面举例说明:

  1. 编写用户持久层Dao接口;

    public interface IUserDao {
        // 根据ID查询用户
        User findUserById(Integer id);
    }
    
  2. 编写持久层映射文件;

    <?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.ben.dao.IUserDao">
        <!-- 配置 查询结果的列名和实体类的属性名的对应关系 -->
        <resultMap id="userMap" type="uSer">
            <!-- 主键字段的对应 -->
            <id property="userId" column="id"></id>
            <!--非主键字段的对应-->
            <result property="userName" column="username"></result>
            <result property="userAddress" column="address"></result>
            <result property="userSex" column="sex"></result>
            <result property="userBirthday" column="birthday"></result>
        </resultMap>
    
        <!-- 查询所有 -->
        <select id="findUserById" resultMap="userMap">
            select * from user where id = #{v};
        </select>
    
    </mapper>
    

  3. 编写测试方法

    public class MybatisTest {
    
        private SqlSessionFactory factory;
        private IUserDao userdao;
        private InputStream in;
        private SqlSession session;
    
        // 作用:在测试方法前执行这个方法
        @Before
        public void setUp() throws Exception {
            //1.读取配置文件
            in = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.创建SqlSessionFactory工厂
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.创建SqlSession工厂对象
            factory = builder.build(in);
            //4.使用工厂生产SqlSession对象
            session = factory.openSession();
            //5.创建Dao接口的代理对象
            userdao = session.getMapper(IUserDao.class);
        }
    
        @After//在测试方法执行完成之后执行
        public void destroy() throws IOException {
            session.close();
            in.close();
        }
    
        // 根据用户ID查找用户
        @Test
        public void testFindUserById(){
            User user1 = userdao.findUserById(41);
            System.out.println(user1);
    
            session.close();
    
            //再次生产SqlSession对象
            session = factory.openSession();
            userdao = session.getMapper(IUserDao.class);
    
            User user2 = userdao.findUserById(41);
            System.out.println(user2);
    
            System.out.println(user1 == user2);
    
        }
    }
    

​ 当执行sqlSession.close()后,再次获取sqlSession并查询id=41的User对象时,又重新执行了sql语句,从数据

库进行了查询操作。 结果发现,两次拿到的数据不一样。

此外还可以通过 session.clearCache()清空一级缓存。

// 根据用户ID查找用户
@Test
public void testFindUserById() {
    User user1 = userdao.findUserById(41);
    System.out.println(user1);

//        session.close();
    session.clearCache();
    //再次生产SqlSession对象
    session = factory.openSession();
    userdao = session.getMapper(IUserDao.class);

    User user2 = userdao.findUserById(41);
    System.out.println(user2);

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

二级缓存

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

使用步骤:

  1. 让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)

    <!--    配置缓存-->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    
  2. 让当前的映射文件支持二级缓存(在IUserDao.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.ben.dao.IUserDao">
        <cache/>
        <!-- 配置 查询结果的列名和实体类的属性名的对应关系 -->
        <resultMap id="userMap" type="uSer">
            <!-- 主键字段的对应 -->
            <id property="userId" column="id"></id>
            <!--非主键字段的对应-->
            <result property="userName" column="username"></result>
            <result property="userAddress" column="address"></result>
            <result property="userSex" column="sex"></result>
            <result property="userBirthday" column="birthday"></result>
        </resultMap>
    
        <!-- 查询所有 -->
        <select id="findUserById" resultMap="userMap" useCache="true">
            select * from user where id = #{v};
        </select>
    </mapper>
    
  3. 让当前的操作支持二级缓存(在select标签中配置) useCache="true"

编写测试类

@Test
public void testSecondCache() {
    SqlSession session = factory.openSession();
    IUserDao dao1 = session.getMapper(IUserDao.class);
    User user1 = dao1.findUserById(41);
    System.out.println(user1);
    //一级缓存消失
    session.close();
//        session.clearCache();
    //再次生产SqlSession对象
    SqlSession session2 = factory.openSession();
    IUserDao dao2 = session2.getMapper(IUserDao.class);

    User user2 = dao2.findUserById(41);
    System.out.println(user2);
    session.close();

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

}

经过上面的测试,我们发现执行了两次查询,并且在执行第一次查询后,我们关闭了一级缓存,再去执行第二
次查询时,我们发现并没有对数据库发出 sql 语句,所以此时的数据就只能是来自于我们所说的二级缓存。 第二次直接从二级缓存中拿到的数据。

二级缓存图解:二级缓存存放的内容是数据,而不是对象。

posted @ 2019-07-20 15:22  伊万夫斯基  阅读(275)  评论(0编辑  收藏  举报