mybatis进阶(8)--查询缓存之二级缓存

来源:互联网 发布:android源码语法 编辑:程序博客网 时间:2024/05/15 23:45

话不多说看图:
这里写图片描述

上节中提到,二级缓存是mapper级别的。可以跨sqlSession使用。

过程分析:

首先我们需要手动开启mybatis的二级缓存
sqlSession1发起查询用户id为1的用户信息,先去缓存中后是否有id为1的用户信息,如果没有,从数据库查询用户信息,并将用户信息存储到二级缓存中去
如果sqlSession3去执行相同mapper下的commit操作(插入,更新,删除),清空sqlSession的二级缓存
sqlSession2发起查询用户id为1的用户信息,先去缓存中后是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。

二级缓存和一级缓存的区别:

二级缓存的范围更大,多个sqlSession共享一个userMapper的二级缓存
userMapper有一个二级缓存区域(按namespace分),其他的mapper也有自己的二级缓存区域
每个namespace的mapper都有一个二级缓存区域,两个mapper的namespace如果相同,那么这两个mapper执行sql查询将数据存在相同的二级缓存中去

1.开启二级缓存:
二级缓存是mapper范围级别,除了在sqlMapConfig.xml中配置二级缓存开关,还需要在具体的mapper.xml中开启二级缓存
在sqlMapConfig.xml中的settings中配置

<settings>        <!-- 打开延迟加载开关 -->        <setting name="lazyLoadingEnabled" value="true"/>        <!-- 将积极加载改变成消极加载,也就是需要时加载 -->        <setting name="aggressiveLazyLoading" value="false"/>        <!-- 开启二级缓存 -->        <setting name="cacheEnabled" value="true"/>    </settings>

在userMapper.xml中开启二级缓存,它里面的sql执行完会存储到它的缓存区域(hashmap)中

<!-- 开启本mapper的namespace下的二级缓存 -->    <cache></cache>

2.调用pojo类的实现序列化接口

public class User implements Serializable{...}

为了将缓存数据去除执行反序列化,因为为二级缓存数据存储介质不一样
3.测试二级缓存

先来测试下两次请求查询的执行结果

// 测试二级缓存    @Test    public void testCache2() throws Exception {        SqlSession sqlSession1 = sqlSessionFactory.openSession();        SqlSession sqlSession2 = sqlSessionFactory.openSession();        SqlSession sqlSession3 = sqlSessionFactory.openSession();        // 获取代理对象        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);        // 使用sqlSession1        // 第一次发起请求查询用户id为1的用户        User u = userMapper1.findUserById(1);        System.out.println(u);        // 这里执行关闭操作,将sqlSession1中的数据写到二级缓存        sqlSession1.close();        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);        // 使用sqlSession2        // 第2次发起请求查询用户id为1的用户        User u2 = userMapper2.findUserById(1);        System.out.println(u2);        sqlSession2.close();    }

执行结果:

Cache Hit Ratio [com.ddd.mybatis.mapper.UserMapper]: 0.02017-07-19 08:54:19,761 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Opening JDBC Connection2017-07-19 08:54:20,006 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Created connection 762493988.2017-07-19 08:54:20,006 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@2d72bc24]2017-07-19 08:54:20,008 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] ==>  Preparing: SELECT * FROM USER WHERE id=? 2017-07-19 08:54:20,074 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] ==> Parameters: 1(Integer)2017-07-19 08:54:20,100 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] <==      Total: 1User [id=1, username=林更新, sex=男, birthday=Tue Jul 18 00:00:00 CST 2017, address=北京市海淀区, ordersList=null]2017-07-19 08:54:20,111 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@2d72bc24]2017-07-19 08:54:20,112 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@2d72bc24]2017-07-19 08:54:20,113 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Returned connection 762493988 to pool.2017-07-19 08:54:20,134 [main] [com.ddd.mybatis.mapper.UserMapper]-[DEBUG] Cache Hit Ratio [com.ddd.mybatis.mapper.UserMapper]: 0.5User [id=1, username=林更新, sex=男, birthday=Tue Jul 18 00:00:00 CST 2017, address=北京市海淀区, ordersList=null]

可以看出来,Cache Hit Ratio [com.ddd.mybatis.mapper.UserMapper]: 0.0表示缓存命中率为0,因为第一次在缓存中没有找到,所以去数据库中找,发出了sql语句,第二次找就直接在缓存中找,然后命中,两次找到一次,所以命中率为0.5

再来测试3个有查询有提交的:

// 测试二级缓存    @Test    public void testCache2() throws Exception {        SqlSession sqlSession1 = sqlSessionFactory.openSession();        SqlSession sqlSession2 = sqlSessionFactory.openSession();        SqlSession sqlSession3 = sqlSessionFactory.openSession();        // 获取代理对象        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);        // 使用sqlSession1        // 第一次发起请求查询用户id为1的用户        User u = userMapper1.findUserById(1);        System.out.println(u);        // 这里执行关闭操作,将sqlSession1中的数据写到二级缓存        sqlSession1.close();        // 获取代理对象        UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);        // 使用sqlSession3        // 第2次发起请求查询用户id为1的用户        User u3 = userMapper3.findUserById(1);        u3.setUsername("王思聪");        userMapper3.updateUser(u3);        sqlSession3.commit();        System.out.println(u3);        // 这里执行关闭操作,将sqlSession3中的数据写到二级缓存        sqlSession3.close();        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);        // 使用sqlSession2        // 第3次发起请求查询用户id为1的用户        User u2 = userMapper2.findUserById(1);        System.out.println(u2);        sqlSession2.close();    }
Cache Hit Ratio [com.ddd.mybatis.mapper.UserMapper]: 0.02017-07-19 09:01:15,731 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Opening JDBC Connection2017-07-19 09:01:15,983 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Created connection 1019014919.2017-07-19 09:01:15,983 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3cbcef07]2017-07-19 09:01:15,986 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] ==>  Preparing: SELECT * FROM USER WHERE id=? 2017-07-19 09:01:16,042 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] ==> Parameters: 1(Integer)2017-07-19 09:01:16,064 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] <==      Total: 1User [id=1, username=林更新, sex=男, birthday=Tue Jul 18 00:00:00 CST 2017, address=北京市海淀区, ordersList=null]2017-07-19 09:01:16,072 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3cbcef07]2017-07-19 09:01:16,072 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3cbcef07]2017-07-19 09:01:16,072 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Returned connection 1019014919 to pool.2017-07-19 09:01:16,075 [main] [com.ddd.mybatis.mapper.UserMapper]-[DEBUG] Cache Hit Ratio [com.ddd.mybatis.mapper.UserMapper]: 0.52017-07-19 09:01:16,075 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Opening JDBC Connection2017-07-19 09:01:16,075 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Checked out connection 1019014919 from pool.2017-07-19 09:01:16,076 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3cbcef07]2017-07-19 09:01:16,076 [main] [com.ddd.mybatis.mapper.UserMapper.updateUser]-[DEBUG] ==>  Preparing: UPDATE USER SET username=?,birthday=?,sex=?,address=? WHERE id=? 2017-07-19 09:01:16,079 [main] [com.ddd.mybatis.mapper.UserMapper.updateUser]-[DEBUG] ==> Parameters: 王思聪(String), 2017-07-18 00:00:00.0(Timestamp), 男(String), 北京市海淀区(String), 1(Integer)2017-07-19 09:01:16,080 [main] [com.ddd.mybatis.mapper.UserMapper.updateUser]-[DEBUG] <==    Updates: 12017-07-19 09:01:16,080 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3cbcef07]User [id=1, username=王思聪, sex=男, birthday=Tue Jul 18 00:00:00 CST 2017, address=北京市海淀区, ordersList=null]2017-07-19 09:01:16,140 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3cbcef07]2017-07-19 09:01:16,141 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3cbcef07]2017-07-19 09:01:16,141 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Returned connection 1019014919 to pool.2017-07-19 09:01:16,141 [main] [com.ddd.mybatis.mapper.UserMapper]-[DEBUG] Cache Hit Ratio [com.ddd.mybatis.mapper.UserMapper]: 0.33333333333333332017-07-19 09:01:16,141 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Opening JDBC Connection2017-07-19 09:01:16,141 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Checked out connection 1019014919 from pool.2017-07-19 09:01:16,142 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3cbcef07]2017-07-19 09:01:16,142 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] ==>  Preparing: SELECT * FROM USER WHERE id=? 2017-07-19 09:01:16,143 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] ==> Parameters: 1(Integer)2017-07-19 09:01:16,145 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] <==      Total: 1User [id=1, username=王思聪, sex=男, birthday=Tue Jul 18 00:00:00 CST 2017, address=北京市海淀区, ordersList=null]

当sqlSession3提交后,将会清空二级缓存,下次查将查最新的数据,所以第三次查询会发出sql代码

4.禁用二级缓存
在statement中设置useCache=”false”将会禁用二级缓存,每次查询都会发出sql去查询,默认是true,即该sql使用二级缓存

应用场合:针对每次查询都需要最新数据sql,要设置禁用二级缓存

5.刷新缓存(就是清空缓存)
在同一namespace下的mapper中,如果有增删改操作后需要刷新缓存,避免脏读

在statement中设置flushCache=”false”将会不刷新缓存,他默认是true。如果设置为false,在我们手动更改数据库中的查询数据会出现脏读

一般执行完commit操作都要执行刷新缓存,防止脏读数据。