上节中提到,二级缓存是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)中
<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.0
2017-07-19 08:54:19,761 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Opening JDBC Connection
2017-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: 1
User [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.5
User [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.0
2017-07-19 09:01:15,731 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Opening JDBC Connection
2017-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: 1
User [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.5
2017-07-19 09:01:16,075 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Opening JDBC Connection
2017-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: 1
2017-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.3333333333333333
2017-07-19 09:01:16,141 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Opening JDBC Connection
2017-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: 1
User [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操作都要执行刷新缓存,防止脏读数据。