你未必出类拔萃,但一定与众不同
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的。