mybaties查询缓存
来源:互联网 发布:订单号生成算法 编辑:程序博客网 时间:2024/05/21 11:03
一 Mybaties查询缓存
mybatis提供查询缓存,如果缓存中有数据就不用从数据库中获取,用于减轻数据压力,提高系统性能。
Mybaties缓存模型
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
1.1 一级缓存:
如上图所示:第一次查询的时候,根据用户id查询用户信息,先查询缓存,在一级缓存没有查询到用户信息,从数据库查询,查询到用户信息之后,放入缓存进行存储。
如果中途有crud操作进行,就清空缓存,防止出现脏读的情况。
如上图所示:第二次以相同的id查询用户信息时,先查询缓存,如果缓存中已经有了,就直接返回,提高查询效率,如果缓存中没有的话,就查询数据库,走相同的过程。
测试一级缓存
public void testOneLevelCache() {SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);// 第一次查询ID为1的用户,去缓存找,找不到就去查找数据库User user1 = mapper.findUserById(1);System.out.println(user1);// 第二次查询ID为1的用户User user2 = mapper.findUserById(1);System.out.println(user2);sqlSession.close();}
如图所示两次查询只输出了一条查询语句。
@Testpublic void testOneLevelCache() {SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);// 第一次查询ID为1的用户,去缓存找,找不到就去查找数据库User user1 = mapper.findUserById(1);System.out.println(user1);User user = new User();user.setUsername("东哥1");user.setAddress("清河宝盛西里");//执行增删改操作,清空缓存mapper.insertUser(user);// 第二次查询ID为1的用户User user2 = mapper.findUserById(1);System.out.println(user2);sqlSession.close();}
如上图所示:由于插入操作的时候把缓存清空了,所以发送了两条SQL语句进行查询。
正式开发中:
将mybatis和spring进行整合开发,事务控制在service中。
一个service方法中包括很多mapper方法调用。
service{
//开始执行时,开启事务,创建SqlSession对象
//第一次调用mapper的方法findUserById(1)
//第二次调用mapper的方法findUserById(1),从一级缓存中取数据
//方法结束,sqlSession关闭
}
如果是执行两次service调用查询相同的用户信息,不走一级缓存,因为session方法结束,sqlSession就关闭,一级缓存就清空。
1.2 二级缓存:
第一次调用mapper下的sql去查询用户信息时,查询结果会存放在二级缓中。
第二次调用相同的namespace下的mapper映射文件去执行相同的sql时,会去对应的缓存中取结果。
如果调用相同的namespace下的mapper进行增删改的话就会清空二级缓存。
开启二级缓存。
1、 在核心配置文件SqlMapConfig.xml中加入以下内容(开启二级缓存总开关):
在settings标签中添加以下内容:
<!-- 开启二级缓存总开关 --><setting name="cacheEnabled" value="true"/>2. 在UserMapper映射文件中,加入以下内容,开启二级缓存:
<!-- 开启本mapper下的namespace的二级缓存,默认使用的是mybatis提供的PerpetualCache --><cache></cache>
由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,所以需要给缓存的对象执行序列化。
如果该类存在父类,那么父类也要实现序列化。
@Testpublic void testTwoLevelCache() {SqlSession sqlSession1 = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();SqlSession sqlSession3 = sqlSessionFactory.openSession();UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);// 第一次查询ID为1的用户,去缓存找,找不到就去查找数据库User user1 = mapper1.findUserById(1);System.out.println(user1);// 关闭SqlSession1sqlSession1.close();// 第二次查询ID为1的用户User user2 = mapper2.findUserById(1);System.out.println(user2);// 关闭SqlSession2sqlSession2.close();}
如上图所示,两个不同的mapper去取相同的命名空间,查询二级缓存,并且产生了缓存命中率。