1.what?
mybatis提供查询缓存,用于减轻数据压力,提高数据库性能
mybatis提供一级缓存,二级缓存
话不多说看图:
我们之前的测试中总是需要SQLSession来操作数据库,而这个sqlSession中有这样一个hashmap的数据结构用来存储缓存数据。
不同的sqlSession之间的缓存区域(hashmap)是互不影响的。
二级缓存是mapper级别的缓存,可以跨sqlSession,多个sqlSession去操作数据库会存储在二级缓存区域,多个sqlSession可以共用二级缓存
2.why?
为啥啊?
要是缓存中有我们要的数据就不用在数据库中获取,我们就不用访问系统了,这大大提高了系统的性能。
下图为根据id查询用户的一级缓存图解
第一次:
发起查询用户id为1的用户信息,先去缓存中后是否有id为1的用户信息,如果没有,从数据库查询用户信息,并将用户信息存储到一级缓存中去
如果sqlSession去执行commit操作(插入,更新,删除),清空sqlSession的一级缓存,这样是为了让缓存中存储的是最新的信息,避免脏读
第二次:
发起查询用户id为1的用户信息,先去缓存中后是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
3.how?
mybatis默认提供缓存
来测试下:
@Test
public void testCache1() throws Exception {
SqlSession sqlSession=sqlSessionFactory.openSession();
//获取代理对象
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//使用一个sqlSession
//第一次发起请求查询用户id为1的用户
User u=userMapper.findUserById(1);
System.out.println(u);
//第二次发起请求查询用户id为1的用户
User u2=userMapper.findUserById(1);
System.out.println(u2);
sqlSession.close();
}
来看看结果:
Preparing: SELECT * FROM USER WHERE id=?
2017-07-18 21:42:58,010 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] ==> Parameters: 1(Integer)
2017-07-18 21:42:58,040 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] <== Total: 1
User [id=1, username=小明, sex=男, birthday=Fri Sep 09 00:00:00 CST 2011, address=北京市海淀区, ordersList=null]
User [id=1, username=小明, sex=男, birthday=Fri Sep 09 00:00:00 CST 2011, address=北京市海淀区, ordersList=null]
可以看出我们的sql代码之发出了一次
那再来测试下更新操作
@Test
public void testCache1() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 使用一个sqlSession
// 第一次发起请求查询用户id为1的用户
User u = userMapper.findUserById(1);
System.out.println(u);
// 如果sqlSession去执行commit操作(插入,更新,删除),清空sqlSession的一级缓存,这样是为了让缓存中存储的是最新的信息,避免脏读
u.setUsername("林更新");
u.setBirthday(new Date());
u.setSex("男");
userMapper.updateUser(u);
sqlSession.commit();
// 第二次发起请求查询用户id为1的用户
User u2 = userMapper.findUserById(1);
System.out.println(u2);
sqlSession.close();
}
看下控制台是怎么执行sql的:
Preparing: SELECT * FROM USER WHERE id=?
2017-07-18 21:49:15,200 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] ==> Parameters: 1(Integer)
2017-07-18 21:49:15,231 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] <== Total: 1
User [id=1, username=小明, sex=男, birthday=Fri Sep 09 00:00:00 CST 2011, address=北京市海淀区, ordersList=null]
2017-07-18 21:49:15,235 [main] [com.ddd.mybatis.mapper.UserMapper.updateUser]-[DEBUG] ==> Preparing: UPDATE USER SET username=?,birthday=?,sex=?,address=? WHERE id=?
2017-07-18 21:49:15,237 [main] [com.ddd.mybatis.mapper.UserMapper.updateUser]-[DEBUG] ==> Parameters: 林更新(String), 2017-07-18 21:49:15.234(Timestamp), 男(String), 北京市海淀区(String), 1(Integer)
2017-07-18 21:49:16,201 [main] [com.ddd.mybatis.mapper.UserMapper.updateUser]-[DEBUG] <== Updates: 1
2017-07-18 21:49:16,201 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@5c4d2a5a]
2017-07-18 21:49:16,495 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] ==> Preparing: SELECT * FROM USER WHERE id=?
2017-07-18 21:49:16,495 [main] [com.ddd.mybatis.mapper.UserMapper.findUserById]-[DEBUG] ==> Parameters: 1(Integer)
2017-07-18 21:49:16,497 [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]
可以看出在commit后缓存清空,第二次查询时,继续发出sql代码访问数据库。
mybatis一级缓存(localcache)的内部是hashmap,他会根据statement的id,还有查询参数动态拼接一个作为key,这样下次如果是相同的key那就直接返回。
4.应用
正式开发是将mybatis和spring整合开发,事务控制在service中
一个service中包括很多mapper方法的调用
service
Service1{
//开始执行时,事务开启,创建sqlSession对象
//第一次调用mapper的方法findUserById(1)
//第二次调用mapper的方法findUserById(1)
//方法结束,sqlSession关闭
}
如果执行2次Service调用查询相同的用户信息,不会走一级缓存,因为service方法结束,sqlSession就关闭,一级缓存就清空
此时就需要二级缓存。