Mybatis的一级缓存和二级缓存探索

11 篇文章 0 订阅

你未必出类拔萃,但一定与众不同

Mybatis的一级缓存和二级缓存探索

概述

SqlSession的作用

  • 获取Mapper接口
  • 发送Sql给数据库
  • 控制数据库事务

关闭二级缓存

关闭二级缓存,默认开启一级缓存的时候 同一个SqlSession

测试代码

		String resources = "mybatis-config.xml";
        InputStream in = Resources.getResourceAsStream(resources);
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
        SqlSession sqlSession = sessionFactory.openSession(true);
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        long s1 = System.currentTimeMillis();
        List<User> userList = mapper.selectUser();
        long e1 =System.currentTimeMillis();
        System.out.println("第一次查询时间:"+(e1-s1));

        long s2 = System.currentTimeMillis();
        List<User> userList1 = mapper.selectUser();
        long e2 =System.currentTimeMillis();
        System.out.println("第二次查询时间:"+(e2-s2));
2021-07-25 12:48:45.304 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ooo Using Connection [com.mysql.cj.jdbc.ConnectionImpl@6815c5f2]
2021-07-25 12:48:45.304 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==>  Preparing: select * from user 
2021-07-25 12:48:45.336 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==> Parameters: 
第一次查询时间:2372
第二次查询时间:0
User(id=41, username=老王, sex=, address=北京)
User(id=42, username=老二, sex=, address=北京)
User(id=43, username=老三, sex=, address=上海)
User(id=44, username=老四, sex=, address=北京)
User(id=45, username=老五, sex=, address=上海)
User(id=46, username=老六, sex=, address=北京)
2021-07-25 12:48:45.367 DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction ------ Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@6815c5f2]
2021-07-25 12:48:45.367 DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource ------ Returned connection 1746257394 to pool.

第一次查询的时候 执行了sql语句,第二次则直接从缓存中取

一级缓存生效

关闭二级缓存,默认开启一级缓存的时候,不同的SqlSession

        String resources = "mybatis-config.xml";
        InputStream in = Resources.getResourceAsStream(resources);
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
        SqlSession sqlSession = sessionFactory.openSession(true);
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        long s1 = System.currentTimeMillis();
        List<User> userList = mapper.selectUser();
        long e1 =System.currentTimeMillis();
        System.out.println("userList查询时间:"+(e1-s1));
        for(User user:userList){
            System.out.println(user);
        }
        System.out.println("不同SqlSession 但是在同一SqlSessionFactory生命周期");

        SqlSession sqlSession2 = sessionFactory.openSession(true);
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        long s2 = System.currentTimeMillis();
        List<User> userList2 = mapper2.selectUser();
        long e2 =System.currentTimeMillis();
        System.out.println("userList2查询时间:"+(e2-s2));
        for(User user:userList2){
            System.out.println(user);
        }

此时明显看出,在不同的SqlSession情况下,且当前二级缓存关闭,执行了两次查询Sql语句

一级缓存失效

2021-07-25 12:53:17.657 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ooo Using Connection [com.mysql.cj.jdbc.ConnectionImpl@6815c5f2]
2021-07-25 12:53:17.658 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==>  Preparing: select * from user 
2021-07-25 12:53:17.686 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==> Parameters: 
userList查询时间:2249
User(id=41, username=老王, sex=, address=北京)
User(id=42, username=老二, sex=, address=北京)
User(id=43, username=老三, sex=, address=上海)
User(id=44, username=老四, sex=, address=北京)
User(id=45, username=老五, sex=, address=上海)
User(id=46, username=老六, sex=, address=北京)
不同SqlSession 但是在同一SqlSessionFactory生命周期
2021-07-25 12:53:17.715 DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction ------ Opening JDBC Connection
2021-07-25 12:53:17.724 DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource ------ Created connection 1882116496.
2021-07-25 12:53:17.724 DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction ------ Setting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@702ed190]
2021-07-25 12:53:17.725 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ooo Using Connection [com.mysql.cj.jdbc.ConnectionImpl@702ed190]
2021-07-25 12:53:17.725 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==>  Preparing: select * from user 
2021-07-25 12:53:17.725 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==> Parameters: 
userList2查询时间:11
User(id=41, username=老王, sex=, address=北京)
User(id=42, username=老二, sex=, address=北京)
User(id=43, username=老三, sex=, address=上海)
User(id=44, username=老四, sex=, address=北京)
User(id=45, username=老五, sex=, address=上海)
User(id=46, username=老六, sex=, address=北京)

开启二级缓存

<settings>
    <!--这个配置使全局的映射器(二级缓存)启用或禁用缓存-->
    <setting name="cacheEnabled" value="true" />
</settings>
<cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>

开启二级缓存时,不同的SqlSession下

String resources = "mybatis-config.xml";
InputStream in = Resources.getResourceAsStream(resources);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = sessionFactory.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);

long s1 = System.currentTimeMillis();
List<User> userList = mapper.selectUser();
long e1 =System.currentTimeMillis();
System.out.println("userList查询时间:"+(e1-s1));
for(User user:userList){
    System.out.println(user);
}
System.out.println("不同SqlSession 但是在同一SqlSessionFactory生命周期");
sqlSession.close();
SqlSession sqlSession2 = sessionFactory.openSession(true);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
long s2 = System.currentTimeMillis();
List<User> userList2 = mapper2.selectUser();
long e2 =System.currentTimeMillis();
System.out.println("userList2查询时间:"+(e2-s2));
for(User user:userList2){
    System.out.println(user);
}

只执行了一次查询,第二次查询时间为0 利用了二级缓存 说明二级缓存在同一个sessionFactory下共享SqlSession

2021-07-25 13:01:50.539 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ooo Using Connection [com.mysql.cj.jdbc.ConnectionImpl@1c32886a]
2021-07-25 13:01:50.540 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==>  Preparing: select * from user 
2021-07-25 13:01:50.569 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==> Parameters: 
userList查询时间:2207
User(id=41, username=老王, sex=, address=北京)
User(id=42, username=老二, sex=, address=北京)
User(id=43, username=老三, sex=, address=上海)
User(id=44, username=老四, sex=, address=北京)
User(id=45, username=老五, sex=, address=上海)
User(id=46, username=老六, sex=, address=北京)
不同SqlSession 但是在同一SqlSessionFactory生命周期
2021-07-25 13:01:50.595 DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction ------ Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1c32886a]
2021-07-25 13:01:50.596 DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource ------ Returned connection 473073770 to pool.
2021-07-25 13:01:50.596 DEBUG org.apache.ibatis.cache.decorators.LoggingCache ------ Cache Hit Ratio [com.wjc.mapper.UserMapper]: 0.5
userList2查询时间:0
User(id=41, username=老王, sex=, address=北京)
User(id=42, username=老二, sex=, address=北京)
User(id=43, username=老三, sex=, address=上海)
User(id=44, username=老四, sex=, address=北京)
User(id=45, username=老五, sex=, address=上海)
User(id=46, username=老六, sex=, address=北京)

开启二级缓存的时候 新建新的SqlSessionFactory

String resources = "mybatis-config.xml";
InputStream in = Resources.getResourceAsStream(resources);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = sessionFactory.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);

long s1 = System.currentTimeMillis();
List<User> userList = mapper.selectUser();
long e1 =System.currentTimeMillis();
System.out.println("userList查询时间:"+(e1-s1));
for(User user:userList){
    System.out.println(user);
}
System.out.println("不同SqlSession 但是在同一SqlSessionFactory生命周期");
sqlSession.close();
SqlSession sqlSession2 = sessionFactory.openSession(true);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
long s2 = System.currentTimeMillis();
List<User> userList2 = mapper2.selectUser();
long e2 =System.currentTimeMillis();
System.out.println("userList2查询时间:"+(e2-s2));
for(User user:userList2){
    System.out.println(user);
}


System.out.println("关闭SqlSessionFactory,在新的SqlSessionFactory生命周期");
String resources2 = "mybatis-config.xml";
InputStream in2 = Resources.getResourceAsStream(resources2);
SqlSessionFactory sessionFactory1 = new SqlSessionFactoryBuilder().build(in2);
SqlSession sqlSession3 = sessionFactory1.openSession(true);
UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);
long s3 = System.currentTimeMillis();
List<User> userList3 = mapper3.selectUser();
long e3 =System.currentTimeMillis();
System.out.println("userList2查询时间:"+(e3-s3));
for (User user : userList3) {
    System.out.println(user);
}

此时新的在SqlSessionFactory里重新执行了查询,二级缓存未生效(二级缓存作用域为 同一个nameSpace)

2021-07-25 13:05:51.519 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ooo Using Connection [com.mysql.cj.jdbc.ConnectionImpl@1c32886a]
2021-07-25 13:05:51.520 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==>  Preparing: select * from user 
2021-07-25 13:05:51.549 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==> Parameters: 
userList查询时间:2320
User(id=41, username=老王, sex=, address=北京)
User(id=42, username=老二, sex=, address=北京)
User(id=43, username=老三, sex=, address=上海)
User(id=44, username=老四, sex=, address=北京)
User(id=45, username=老五, sex=, address=上海)
User(id=46, username=老六, sex=, address=北京)
不同SqlSession 但是在同一SqlSessionFactory生命周期
2021-07-25 13:05:51.579 DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction ------ Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1c32886a]
2021-07-25 13:05:51.579 DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource ------ Returned connection 473073770 to pool.
2021-07-25 13:05:51.579 DEBUG org.apache.ibatis.cache.decorators.LoggingCache ------ Cache Hit Ratio [com.wjc.mapper.UserMapper]: 0.5
userList2查询时间:0
User(id=41, username=老王, sex=, address=北京)
User(id=42, username=老二, sex=, address=北京)
User(id=43, username=老三, sex=, address=上海)
User(id=44, username=老四, sex=, address=北京)
User(id=45, username=老五, sex=, address=上海)
User(id=46, username=老六, sex=, address=北京)
关闭SqlSessionFactory,在新的SqlSessionFactory生命周期
2021-07-25 13:05:51.597 DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction ------ Opening JDBC Connection
2021-07-25 13:05:51.606 DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource ------ Created connection 1540476618.
2021-07-25 13:05:51.606 DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction ------ Setting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5bd1ceca]
2021-07-25 13:05:51.607 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ooo Using Connection [com.mysql.cj.jdbc.ConnectionImpl@5bd1ceca]
2021-07-25 13:05:51.607 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==>  Preparing: select * from user 
2021-07-25 13:05:51.607 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==> Parameters: 
userList2查询时间:11
User(id=41, username=老王, sex=, address=北京)
User(id=42, username=老二, sex=, address=北京)
User(id=43, username=老三, sex=, address=上海)
User(id=44, username=老四, sex=, address=北京)
User(id=45, username=老五, sex=, address=上海)
User(id=46, username=老六, sex=, address=北京)

开启二级缓存,不同的nameSpace下 不同的SqlSession

我们新建一个userMapper2和userMapper一模一样,然后新建一个usermapper2.xml和usermapper.xml一样,但是namespace不同

不同的nameSpace下 不同的SqlSession 还是执行了两次sql 而上方的二级缓存生效都是在同一个namespace下

String resources = "mybatis-config.xml";
InputStream in = Resources.getResourceAsStream(resources);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = sessionFactory.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);

long s1 = System.currentTimeMillis();
List<User> userList = mapper.selectUser();
long e1 =System.currentTimeMillis();
System.out.println("userList查询时间:"+(e1-s1));
for(User user:userList){
    System.out.println(user);
}


SqlSession sqlSession3 = sessionFactory.openSession(true);
UserMapper2 mapper3 = sqlSession3.getMapper(UserMapper2.class);
long s3 = System.currentTimeMillis();
List<User> userList3 = mapper3.selectUser();
long e3 =System.currentTimeMillis();
System.out.println("userList3查询时间:"+(e3-s3));
for(User user:userList3){
    System.out.println(user);
}
2021-07-25 13:13:08.034 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ooo Using Connection [com.mysql.cj.jdbc.ConnectionImpl@245a26e1]
2021-07-25 13:13:08.034 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==>  Preparing: select * from user 
2021-07-25 13:13:08.059 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==> Parameters: 
userList查询时间:2085
User(id=41, username=老王, sex=, address=北京)
User(id=42, username=老二, sex=, address=北京)
User(id=43, username=老三, sex=, address=上海)
User(id=44, username=老四, sex=, address=北京)
User(id=45, username=老五, sex=, address=上海)
User(id=46, username=老六, sex=, address=北京)
2021-07-25 13:13:08.088 DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction ------ Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@245a26e1]
2021-07-25 13:13:08.088 DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource ------ Returned connection 609887969 to pool.
....
2021-07-25 13:13:08.090 DEBUG com.wjc.mapper.UserMapper2.selectUser ------ ooo Using Connection [com.mysql.cj.jdbc.ConnectionImpl@245a26e1]
2021-07-25 13:13:08.090 DEBUG com.wjc.mapper.UserMapper2.selectUser ------ ==>  Preparing: select * from user 
2021-07-25 13:13:08.090 DEBUG com.wjc.mapper.UserMapper2.selectUser ------ ==> Parameters: 
userList3查询时间:3
User(id=41, username=老王, sex=, address=北京)
User(id=42, username=老二, sex=, address=北京)
User(id=43, username=老三, sex=, address=上海)
User(id=44, username=老四, sex=, address=北京)
User(id=45, username=老五, sex=, address=上海)
User(id=46, username=老六, sex=, address=北京)

开启二级缓存,不同的nameSpace下 相同的SqlSession

String resources = "mybatis-config.xml";
        InputStream in = Resources.getResourceAsStream(resources);
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
        SqlSession sqlSession = sessionFactory.openSession(true);
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        long s1 = System.currentTimeMillis();
        List<User> userList = mapper.selectUser();
        long e1 =System.currentTimeMillis();
        System.out.println("userList查询时间:"+(e1-s1));
        for(User user:userList){
            System.out.println(user);
        }

        UserMapper2 mapper3 = sqlSession.getMapper(UserMapper2.class);
        long s3 = System.currentTimeMillis();
        List<User> userList3 = mapper3.selectUser();
        long e3 =System.currentTimeMillis();
        System.out.println("userList3查询时间:"+(e3-s3));
        for(User user:userList3){
            System.out.println(user);
        }

查询同一个表的同一个sql语句还是执行了两次 还是证实了 二级缓存的生效需要在同一个nameSpace下

2021-07-25 13:15:32.858 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ooo Using Connection [com.mysql.cj.jdbc.ConnectionImpl@245a26e1]
2021-07-25 13:15:32.858 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==>  Preparing: select * from user 
2021-07-25 13:15:32.889 DEBUG com.wjc.mapper.UserMapper.selectUser ------ ==> Parameters: 
userList查询时间:2265
User(id=41, username=老王, sex=, address=北京)
User(id=42, username=老二, sex=, address=北京)
User(id=43, username=老三, sex=, address=上海)
User(id=44, username=老四, sex=, address=北京)
User(id=45, username=老五, sex=, address=上海)
User(id=46, username=老六, sex=, address=北京)
2021-07-25 13:15:32.918 DEBUG org.apache.ibatis.cache.decorators.LoggingCache ------ Cache Hit Ratio [com.wjc.mapper.UserMapper2]: 0.0
2021-07-25 13:15:32.918 DEBUG com.wjc.mapper.UserMapper2.selectUser ------ ooo Using Connection [com.mysql.cj.jdbc.ConnectionImpl@245a26e1]
2021-07-25 13:15:32.918 DEBUG com.wjc.mapper.UserMapper2.selectUser ------ ==>  Preparing: select * from user 
2021-07-25 13:15:32.918 DEBUG com.wjc.mapper.UserMapper2.selectUser ------ ==> Parameters: 
userList3查询时间:2
User(id=41, username=老王, sex=, address=北京)
User(id=42, username=老二, sex=, address=北京)
User(id=43, username=老三, sex=, address=上海)
User(id=44, username=老四, sex=, address=北京)
User(id=45, username=老五, sex=, address=上海)
User(id=46, username=老六, sex=, address=北京)

总结

  • Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存

  • 一级缓存只是相对于同一个SqlSession而言。所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。

  • MyBatis的二级缓存需要手动开启

  • MyBatis 的二级缓存是mapper映射级别的缓存,作用域是同一个mapper的namespace ,同一个namespace中查询SQL可以从缓存中命中,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鱼爱吃柚子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值