mybatis缓存的使用

mybatis的缓存分为一级缓存和二级缓存,默认情况下只开启了一级缓存。

一级缓存
测试用的Mapper接口和Mapper映射文件
public interface UserMapper {
    List<User> findAll();
}
<?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.example.mapper.UserMapper">

    <select id="findAll" resultType="user">
        select * from user
    </select>

</mapper>
同一个SqlSession

同一个SqlSession,参数和sql完全一样的情况下,第一次请求会执行sql语句并缓存执行结果,再次请求就不会再次执行sql,而是从缓存结果中获取结果,当然前提是缓存没有过期。

@Test
public void testFindAll(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

    System.out.println("第1次查询");
    List<User> list1 = userMapper.findAll();
    System.out.println(list1);

    System.out.println();
    //Thread.sleep(10000);

    System.out.println("第2次查询");
    List<User> list2 = userMapper.findAll();
    System.out.println(list2);

    sqlSession.close();
}

输出:
第1次查询
DEBUG [main] - ==>  Preparing: select * from user 
DEBUG [main] - ==> Parameters: 
TRACE [main] - <==    Columns: id, username, password
TRACE [main] - <==        Row: 1, Lisi, 123
DEBUG [main] - <==      Total: 1
[User{id=1, username='Lisi', password='123'}]

第2次查询
[User{id=1, username='Lisi', password='123'}]

从输出我们可以看出,第二次查询并没有执行sql,如果还是不确定,可以在第一次查询结束后,休眠10秒,在休眠的这段时间我们手动去修改一下数据,你会发现就算数据库中的数据修改了,第二次查询依然还是原来的数据,再次印证了第二次没有执行sql查询而是使用了缓存。

不同的SqlSession

在同一个SqlSession的情况下,会出现使用缓存的现象,哪如果是不同的SqlSession呢?

@Test
public void testFindAll2() throws InterruptedException {
    System.out.println("第1次查询");
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
    List<User> list1 = userMapper1.findAll();
    System.out.println(list1);

    System.out.println();
    //Thread.sleep(10000);

    System.out.println("第2次查询");
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
    List<User> list2 = userMapper2.findAll();
    System.out.println(list2);

    sqlSession1.close();
    sqlSession2.close();
}

输出:
第1次查询
DEBUG [main] - ==>  Preparing: select * from user 
DEBUG [main] - ==> Parameters: 
TRACE [main] - <==    Columns: id, username, password
TRACE [main] - <==        Row: 1, Lisi, 123
DEBUG [main] - <==      Total: 1
[User{id=1, username='Lisi', password='123'}]

第2次查询
DEBUG [main] - ==>  Preparing: select * from user 
DEBUG [main] - ==> Parameters: 
TRACE [main] - <==    Columns: id, username, password
TRACE [main] - <==        Row: 1, Lisi, 123
DEBUG [main] - <==      Total: 1
[User{id=1, username='Lisi', password='123'}]

从输出我们可以看出不同的SqlSession的两次查询,没有使用缓存,每次都执行了sql语句。

刷新缓存

刷新缓存是清空这个SqlSession的所有缓存。

<?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.example.mapper.UserMapper">

	# 添加flushCache="true",开启刷新缓存
    <select id="findAll" resultType="user" flushCache="true">
        select * from user
    </select>

</mapper>
@Test
public void testFindAll(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

    System.out.println("第1次查询");
    List<User> list1 = userMapper.findAll();
    System.out.println(list1);

    System.out.println();

    System.out.println("第2次查询");
    List<User> list2 = userMapper.findAll();
    System.out.println(list2);

    sqlSession.close();
}

输出:
第1次查询
DEBUG [main] - ==>  Preparing: select * from user 
DEBUG [main] - ==> Parameters: 
TRACE [main] - <==    Columns: id, username, password
TRACE [main] - <==        Row: 1, Lisi, 123
DEBUG [main] - <==      Total: 1
[User{id=1, username='Lisi', password='123'}]

第2次查询
DEBUG [main] - ==>  Preparing: select * from user 
DEBUG [main] - ==> Parameters: 
TRACE [main] - <==    Columns: id, username, password
TRACE [main] - <==        Row: 1, Lisi, 123
DEBUG [main] - <==      Total: 1
[User{id=1, username='Lisi', password='123'}]

从输出结果中我们可以看到,第二次查询并没有使用缓存,也就是不存在缓存。

一级缓存的实现原理
  1. 在同一个SqlSession中,mybatis会把执行的方法和参数通过算法生成缓存的key, 然后key和结果保存到一个Map中
  2. 下次查询的时候,如果缓存中有就是用缓存中的,没有就去数据库查询并放入缓存中
  3. 清空缓存实际就是清空Map中的数据
二级缓存

一级缓存是SqlSession级别的,如果想要多个SqlSession共享缓存,就需要开启二级缓存,二级缓存默认是关闭的。

开启二级缓存

在mybatis.xml全局配置文件中全局开启二级缓存

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

在mapper映射文件中添加cache标签

<?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.example.mapper.UserMapper">

    <cache/>

    <select id="findAll" resultType="user">
        select * from user
    </select>

</mapper>
POJO必须是可序列化的
public class User implements Serializable {

    private int id;
    private String username;
    private String password;

	//省略gettter setter方法
}
测试
@Test
public void testFindAll() throws InterruptedException {
    System.out.println("第1次查询");
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
    List<User> list1 = userMapper1.findAll();
    System.out.println(list1);
    sqlSession1.close();//需要commit或close

    System.out.println();

    System.out.println("第2次查询");
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
    List<User> list2 = userMapper2.findAll();
    System.out.println(list2);

    sqlSession2.close();
}

输出:
第1次查询
DEBUG [main] - Cache Hit Ratio [com.example.mapper.UserMapper]: 0.0
DEBUG [main] - ==>  Preparing: select * from user 
DEBUG [main] - ==> Parameters: 
TRACE [main] - <==    Columns: id, username, password
TRACE [main] - <==        Row: 1, Lisi, 123
DEBUG [main] - <==      Total: 1
[User{id=1, username='Lisi', password='123'}]

第2次查询
DEBUG [main] - Cache Hit Ratio [com.example.mapper.UserMapper]: 0.5
[User{id=1, username='Lisi', password='123'}]

两次查询使用了不同过的SqlSession,第二次查询没有执行sql,使用了二级缓存。

要不要使用二级缓存

要不要使用二级缓存,先了解下二级缓存使用的注意事项

  1. 缓存是以namespace为单位的,不同namespace下的操作互不影响
  2. insert,update,delete操作会清空所在namespace下的全部缓存
  3. 多表操作一定不要使用二级缓存,因为多表操作进行更新操作,一定会产生脏数据

如果你觉得上面的要求你都满足,那么就可以使用二级缓存。

缓存使用流程
  1. 先查询二级缓存,有就使用
  2. 如果二级缓存没有就查询一级缓存
  3. 如果一级缓存有就用,没有就执行sql查询数据库
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值