目录
1.什么是缓存[Cache ]?
缓存是存在内存中的临时数据。
将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
2.为什么使用缓存?(缓存的意义,目的)
减少和数据库的交互次数,减少系统开销,提高系统效率。
3.什么样的数据能使用缓存?
经常查询并且不经常改变的数据。(说白了就是查的数据)
反过头来说,经常改变的数据(也就是增删改的数据)就不适合作为缓存的数据,因为它如果改变一次就缓存一次就会造成系统开销,实属没必要。
4.Mybatis缓存
MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)。
二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
为了提高扩展性,MyBatis定义了缓存接口cache。我们可以通过实现Cache接口来自定义二级缓存
5.Mybatis缓存的适用场景以及测试
一级缓存
让我们来测试一级缓存:
public interface UserMapper {
List<User> getUserById(@Param("id")int id);
}
<mapper namespace="com.kxy.mapper.UserMapper">
<select id="getUserById" resultType="User">
select * from user where id = #{id}
</select>
</mapper>
@Test
public void Test(){
SqlSession sqlSession = MyUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = mapper.getUserById(1);
System.out.println(user1);
System.out.println("============");
User user2 = mapper.getUserById(1);
System.out.println(user2);
System.out.println(user1==user2);
sqlSession.close();
}
可以发现sql只走了一次,这说明当我们第一次查第id为1的User时,只要他没有被改变,就会被存入一级缓存(本地缓存)中,那么如果再查一次它,就不用去执行sql了,而是从一级缓存中去取。这就是一级缓存的作用之一。
比如下面这个例子:我们修改了Test方法,先查id为1的user1,然后查id为2的user2,最后查id为1user3(user3==user1)
@Test
public void Test(){
SqlSession sqlSession = MyUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = mapper.getUserById(1);
System.out.println(user1);
System.out.println("============");
User user2 = mapper.getUserById(2);
System.out.println(user2);
System.out.println(user1==user2);
System.out.println("============");
User user3 = mapper.getUserById(1);
System.out.println(user3);
System.out.println(user1==user3);
sqlSession.close();
}
至于蓝色标记的id为2的user,他并不影响user1存入缓存,为user3去取提供方便的事实。因此也验证了我们那句话:只要他没有被改变(刷新缓存除外),就会被存入一级缓存(本地缓存)中。
6.一级缓存失效的四种情况:
1.一次性查询不同的对象
比如我先查了id为1的user,我又查询了id为2的user,想都不用想,肯定不会缓存。
2.增删改会刷新缓存
public void Test1(){
SqlSession sqlSession = MyUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = mapper.getUserById(1);
System.out.println(user1);
System.out.println("==============");
mapper.updateUserById(new User(2,"kxy","1434134"));
System.out.println("==============");
User user2 = mapper.getUserById(1);
System.out.println(user2);
System.out.println(user1==user2);
sqlSession.commit();
sqlSession.close();
}
像这种情况,增删改操作导致的数据可能会改变原来的数据,即便改变的不是当前对象,也会刷新缓存,从而导致第二次读取执行sql从数据库里重新查了一次。重新开辟了地址给user2,所以use1==user2是false,即他们不是同一个对象。其本质:地址不同,值相同。
由此可见:增删改会刷新缓存,刷新缓存产生新的对象。
3.运行不同的mapper
因为一个mapper对应一个sqlsession(sqlsession.getMapper),而一级缓存的作用范围只在sqlsession(从sqlsession创建到sqlsession关闭),因此运行不同的mapper当然不会实现一级缓存。
4.手动清理缓存
@Test
public void Test1(){
SqlSession sqlSession = MyUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = mapper.getUserById(1);
System.out.println(user1);
sqlSession.clearCache();
System.out.println("==============");
User user2 = mapper.getUserById(1);
System.out.println(user2);
System.out.println(user1==user2);
sqlSession.close();
}
显然sql运行了两次,第二次没有从缓存中拿,是因为缓存被清理了。false是因为从数据库中又查了一遍,从jdbc的角度来讲,他每次查询都产生一个resultset类型的对象,因此对象肯定是新的对象,其本质:地址不同,值相同。
由此可见:清空缓存会产生新的对象。
总结
1.只要他没有被改变(刷新缓存除外),就会被存入一级缓存(本地缓存)中。
2.增删改会刷新缓存,刷新缓存产生新的对象。
3.清空缓存会产生新的对象。
一级缓存失效的四种情况:
1.一次性查询不同的对象。
2.增删改会刷新缓存
3.运行不同的mapper
4.手动清理缓存