Mybatis 中的缓存

1、缓存

缓存

  • 存在与内存中的临时数据。

为什么使用缓存?

  • 减少和数据库的交互次数,提高执行的效率。

什么样的数据能使用缓存

  • 经常查询且不经常改变的
  • 数据的正确与否对最终结果影响不大的

什么样的数据不适用于缓存

  • 经常改变的数据
  • 数据的正确与否对最终结果影响很大的
  • 例如:商品的库存,银行的汇率,股市的牌价

2、一级缓存

什么是一级缓存

它指的是Mybatis中SqlSession对象的缓存,当我们执行查询之后,查询的结果同时会存入到SqlSession一块区域中,该区域的一个结构是Map结构。当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有,有的话直接拿来用。当SqlSession对象关闭时,或者清空缓存,mybatis的一级缓存也就消失了。

代码查看一级缓存

  • 目录结构
    在这里插入图片描述
  • 表结构
    在这里插入图片描述
  • SqlMapConifg.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis主配置文件-->
<configuration>
    <!--配置环境-->
    <environments default="mysql">
<!--        配置mysql环境-->
        <environment id="mysql">
<!--            配置事务类型-->
            <transactionManager type="JDBC"></transactionManager>
<!--            配置数据源(连接池)-->
            <dataSource type="POOLED">
<!--                配置数据库的基本信息-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT"/>
                <property name="username" value="root"/>
                <property name="password" value="111111"/>
            </dataSource>
        </environment>
    </environments>
<!--    指定映射配置文件的位置,映射配置文件指的是每一个dao独立的配置文件-->
    <mappers>
        <package name="com.mybatis.dao"/>
    </mappers>

</configuration>
  • IUserDao接口,在这里只有两个方法。
package com.mybatis.dao;

import com.mybatis.domain.User;

import java.util.List;

public interface IUserDao {
    /**
     * 查询所有用户,以及账户信息
     * @return
     */
    List<User> findAll();

    /**
     * 根据ID查询用户信息
     * @param userId
     * @return
     */
    User findById(Integer userId);
}

  • 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.mybatis.dao.IUserDao">
<!--    查询所有-->
    <select id="findAll" resultType="com.mybatis.domain.User">
        select * from users
    </select>
    <select id="findById" parameterType="INT" resultType="com.mybatis.domain.User">
        select * from users where id = #{uid}
    </select>
</mapper>
  • MybatisTest测试类
package com.mybatis.test;

import com.mybatis.dao.IUserDao;
import com.mybatis.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.Date;
import java.util.List;

public class MybatisTest {
    private InputStream  in;
    private SqlSession session;
    private IUserDao userDao;
    private SqlSessionFactory factory;

    @Before
    public void init() throws Exception {
        this.in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
        System.out.println(in);
        this.factory = factoryBuilder.build(in);
//        this.session = factory.openSession(true);
        this.session = factory.openSession();
        this.userDao = session.getMapper(IUserDao.class);
    }
    @After
    public void destory() throws IOException {
        session.commit();
        this.in.close();
        this.session.close();
    }
    @Test
    public void testCache(){
        User user1  = userDao.findById(8);
        System.out.println(user1);
        session.clearCache();
        User user2  = userDao.findById(8);
        System.out.println(user2);
        System.out.println(user1 == user2);
    }
}
  • 执行完testCache方法后,结果如下:
    在这里插入图片描述
    两个user对象是一样的,说明第一次从数据库中读取后,第二次直接拿的是session的一级缓存。
  • 当我们把testCache的方法改成如下两钟时
public void testCache(){
        User user1  = userDao.findById(8);
        System.out.println(user1);
        session.clearCache();
        User user2  = userDao.findById(8);
        System.out.println(user2);
        System.out.println(user1 == user2);
    }
public void testCache(){
        User user1  = userDao.findById(8);
        System.out.println(user1);
        session.close();
        session = factory.openSession();
        userDao = session.getMapper(IUserDao.class);
        User user2  = userDao.findById(8);
        System.out.println(user2);
        System.out.println(user1 == user2);
    }

此时已经将缓存session关闭或者清空缓存,结果如下:
在这里插入图片描述
此时两个User对象不同,说明是从数据库钟两次读取的结果。

一级缓存如何实现数据同步的呢?

一级缓存是SqlSession范围的缓存,当调用SqlSession的修改、添加、删除,commit(),close()等方法时,就会清空一级缓存。
这样如果更新了数据,就自动清空缓存,下一次读取的时候就在数据库中读取内容。

3、二级缓存

什么是一级缓存

它指的是Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
在这里插入图片描述

二级缓存的使用步骤

  1. 第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
  2. 第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
  3. 第三步:让当前的操作支持二级缓存(在Select标签中配置)

代码查看二级缓存

  • SqlMapConfig.xml
    添加setting标签
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis主配置文件-->
<configuration>
<!--    配置参数-->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    <!--配置环境-->
    <environments default="mysql">
<!--        配置mysql环境-->
        <environment id="mysql">
<!--            配置事务类型-->
            <transactionManager type="JDBC"></transactionManager>
<!--            配置数据源(连接池)-->
            <dataSource type="POOLED">
<!--                配置数据库的基本信息-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT"/>
                <property name="username" value="root"/>
                <property name="password" value="111111"/>
            </dataSource>
        </environment>
    </environments>
<!--    指定映射配置文件的位置,映射配置文件指的是每一个dao独立的配置文件-->
    <mappers>
        <package name="com.mybatis.dao"/>
    </mappers>

</configuration>
  • IUserDao.xml
    添加一个cache标签 ,select标签中添加useCache=“true”
<?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.mybatis.dao.IUserDao">
    <cache/>
<!--    查询所有-->
    <select id="findAll" resultType="com.mybatis.domain.User">
        select * from users
    </select>
    <select id="findById" parameterType="INT" resultType="com.mybatis.domain.User"  useCache="true">
        select * from users where id = #{uid}
    </select>
</mapper>

测试类:
sqlSession1.close();其中这个时关闭一级缓存对二级缓存的影响。

public void testCache(){
        SqlSession sqlSession1 = factory.openSession();
        IUserDao userDao1 = sqlSession1.getMapper(IUserDao.class);
        User user1 = userDao1.findById(8);
        System.out.println(user1);
        sqlSession1.close();

        SqlSession sqlSession2 = factory.openSession();
        IUserDao userDao2 = sqlSession2.getMapper(IUserDao.class);
        User user2 = userDao2.findById(8);
        System.out.println(user2);
        sqlSession2.close();

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

运行结果:

如果有日志的话,会看到该两次查询,只从数据库中查询了一次结果,然后从缓存中拿取。
在这里插入图片描述
user1 与 user2不相同的原因是,我们在数据库中存储的不是一个对象,而是一组数据,可以理解为json格式的数据,当有请求拿缓存中的数据时,直接将数据给他,然后创建出一个新的对象出来。所以虽然是从缓存中拿取,但是两次的对象肯定是不同的。这一点和一级缓存不同,一级缓存在缓存中存储的就是一个对象。有一个请求缓存过来时,直接用一个引用指向该对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值