跟Hibernate一样,MyBatis提供了缓存查询(一级缓存和二级缓存)的功能,用于提高数据库性能,减轻数据库压力。
如图:
一级缓存是SqlSession级别的缓存。在我们利用MyBatis操作数据库时,需要构造SqlSession对象,在对象中有一个HashMap的数据结构用于存储缓存数据,而且不同的SqlSession之间的缓存数据互不影响。
一级缓存的应用
下面在代码中试验一下,MyBatis默认已经开启了一级缓存,所以不需要任何配置。这里只贴上测试的code
实验一:
@Test public void testCache1() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 查询id为1的用户 User user1 = userMapper.selectByPrimaryKey(6); System.out.println(user1.getUsername()); // 查询id为1的用户 User user2 =userMapper.selectByPrimaryKey(6); System.out.println(user2.getUsername()); sqlSession.close(); }
日志:
由日志中可以看到,当在同一个session中连续查找两条相同的数据时,只执行了一条查询语句。
// 测试一级缓存 @Test public void testCache1() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 查询id为1的用户 User user1 = userMapper.selectByPrimaryKey(6); System.out.println(user1.getUsername()); // 更新id为1的用户 user1.setUsername("Danny"); userMapper.updateByPrimaryKey(user1); sqlSession.commit(); // 查询id为1的用户 User user2 =userMapper.selectByPrimaryKey(6); System.out.println(user2.getUsername()); sqlSession.close(); }
日志:
这里第二次查询与第一次查询仍然是相同的数据,但在第二次查询之前,先进行了更新操作,于是第二次查询去一级缓存中并没有查到数据,所以转而去数据库中查找数据。
总结
在上面的实验中,第一次查询到的数据已经被存放在一级缓存中,当再次查询的时候,会先去一级缓存中查找该数据,如果有则直接返回,没有的话才去数据库中查询。而且当SqlSession进行任何增删改的操作(即改变数据)时,会清空一级缓存中的数据,并且由于一级缓存是SqlSession级别的,所以SqlSession关闭后,一级缓存也会被清空。如下图:
MyBatis和Spring整合后,通常将事务控制在service中,此时在service中,方法开始执行时,开启事务,创建SqlSession对象,调用结束时,SqlSession自动关闭。
在同一个service中可能包含多个mapper的操作,比如:
userMapper.selectByPrimaryKey(6);//第一次调用mapper方法 //……其他业务逻辑 userMapper.selectByPrimaryKey(6);//第二次调用mapper方法
这时在同一个service中查询相同用户信息,就会用到一级缓存,因为方法调用结束,SqlSession就会关闭,一级缓存就会清空。但如果是在两个service中查询相同的用户信息,就不会使用一级缓存了,这时可以使用二级缓存(详见下篇文章)。