2021年5月5日星期三

Mybatis的缓存

缓存

1.什么是缓存?

想想我们之前所有的查询最后都要连接数据库,然而连接数据库很耗资源!然后我们要想办法解决: 我们想能不能一次查询的结果,给他暂存在一个可以直接取到的地方,这个地方一般在内存里!放在内存的这一些查询的数据就叫缓存我们再次查询相同数据的时候,直接走缓存,就不用走数据库了
  • 存在内存中的临时数据。
  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

2.为什么使用缓存?

  • 减少和数据库的交互次数,减少系统开销,提高系统效率。

3.什么样的数据能使用缓存?

  • 经常查询并且不经常改变的数据。【可以使用缓存】
  • 不经常查询且经常改变的数据。【不可以使用缓存】

Mybatis缓存

  • Mybatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大地提升查询效率。
  • Mybatis系统中默认定义了两级缓存: 一级缓存二级缓存
    • 默认情况下,只有一级缓存开启。(SqlSession级别地缓存,也称为本地缓存)
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
    • 为了提高扩展性,Mybatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存。

一级缓存:

  • 一级缓存也叫本地缓存:SqlSession
    • 与数据库同一次会话期间查询到的数据会放在本地缓存中。
    • 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库。

注意:一级缓存也就是从拿到SqlSession开始,到SqlSession关闭之间存在!

测试步骤:

1.开启日志!

2.测试在一个SqlSession中查询两次相同记录

@Testpublic void test(){ //一级缓存开始<<================= SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.queryUserById(1); System.out.println(user); System.out.println("========================="); User user2 = mapper.queryUserById(1); System.out.println(user2); System.out.println(user == user2); sqlSession.close(); //一级缓存结束========================>>}

3.查看日志输出

image-20210505181304399

一级缓存失效的情况:

1.查询不同的用户,一级缓存失效

image-20210505181719159

2.增删改操作,可能会改变原来的数据,所以必定会刷新缓存!

下面这段代码,第一次查询id为1的用户,中间更新了id=2的用户信息,再查一次id为1的用户,结果显示不会走一级缓存,还是会查询数据库!

@Testpublic void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.queryUserById(1); System.out.println(user); mapper.updateUser(new User(2,"aaa","bbb")); System.out.println("========================="); User user2 = mapper.queryUserById(1); System.out.println(user2); System.out.println(user == user2); sqlSession.close();}

image-20210505182712304

3.查询不同的mapper.

这个就不用测试了,不同的mapper肯定不会有一级缓存!

4.手动清理缓存

下面手动清理缓存sqlSession.clearCache(),查询id为1的用户信息走了两次数据库,没有走缓存,这样也会使缓存失效!

@Testpublic void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.queryUserById(1); System.out.println(user); //手动清理缓存 sqlSession.clearCache(); System.out.println("========================="); User user2 = mapper.queryUserById(1); System.out.println(user2); System.out.println(user == user2); sqlSession.close();}

image-20210505183151838

小结:一级缓存默认是开启的,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段!

一级缓存就是一个map集合,往map里面放东西,取的时候从map里面取!

二级缓存:

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存

  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存

  • 工作机制

    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中

    • 如果当前会话关闭了,这个会话对应的一级缓存就没了,但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中

    • 新的会话查询信息,就可以从二级缓存中获取内容

    • 不同的mapper查出的数据会放在自己对应的缓存(map)中

测试步骤:

1.在mybatis-config.

<!--显式地开启全局缓存--><setting name="cacheEnabled" value="true"/>

2.在要使用二级缓存的Mapper中开启

<!--在当前Mapper.

也可以自定义一些参数:

<!--在当前Mapper.

3.测试

@Testpublic void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); SqlSession sqlSession2 = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class); User user = mapper.queryUserById(1); System.out.println(user); User user2 = mapper2.queryUserById(1); System.out.println(user2); sqlSession.close(); sqlSession2.close();}

mapper.

image-20210505190800424

不加测试结果,走了两次数据库:

image-20210505190907324

mapper.

如下:当第一个会话关闭的时候,将数据缓存到了二级缓存中,一个会话死了,致使另一个会话也能从缓存中拿到数据,缓存能在不同的会话中取到,作用域提升了一级,所以才叫二级缓存!(当然前提是在同一个mapper里面的方法)

@Testpublic void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); SqlSession sqlSession2 = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.queryUserById(1); System.out.println(user); sqlSession.close(); UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class); User user2 = mapper2.queryUserById(1); System.out.println(user2); System.out.println(user == user2); sqlSession2.close();}

image-20210505191333103

出现的问题:

如果mapper.

<!--在当前Mapper.

测试会报如下这个序列化错误:

image-20210505192209637

因此我们需要为实体类实现序列化接口:

@Data@AllArgsConstructor@NoArgsConstructorpublic class User implements Serializable { private int id; private String name; private String pwd;}

image-20210505192556530

注意:最后的为false是因为一级缓存内容存到了二级缓存中,所以内存地址变化对比为false!

小结:

  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会先放在一级缓存中,只有当会话提交或者关闭的时候,才会提交到二级缓存中!

缓存原理

Mybatis的缓存原理:先看二级缓存中有没有缓存的数据,在看一级缓存有没有,如果都没有再走查询数据库!

image-20210505215621818

自定义缓存-ehcache:

除了上门一级,二级缓存之外,我们可以自定义缓存实现,但是我们不自己写,我们引用一个第三方写好的自定义缓存ehcache!

Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存

使用步骤:

要在我们的程序中使用ehcache,先要导包!

<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache --><dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.2.1</version></dependency>

并且新建一个ehcache.

<?

然后再对应mapper.

<!--在当前Mapper.

然后测试效果跟一级、二级缓存没啥区别:

image-20210505223311268

最后提一句: 我们在工作中会用Redis数据库做缓存!









原文转载:http://www.shaoqun.com/a/722759.html

跨境电商:https://www.ikjzd.com/

点通:https://www.ikjzd.com/w/1913

6pm:https://www.ikjzd.com/w/317


缓存1.什么是缓存?想想我们之前所有的查询最后都要连接数据库,然而连接数据库很耗资源!然后我们要想办法解决:我们想能不能一次查询的结果,给他暂存在一个可以直接取到的地方,这个地方一般在内存里!放在内存的这一些查询的数据就叫缓存我们再次查询相同数据的时候,直接走缓存,就不用走数据库了存在内存中的临时数据。将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询
三维度科技:https://www.ikjzd.com/w/1312
斑马物联网:https://www.ikjzd.com/w/1316
trademanager:https://www.ikjzd.com/w/730
谷歌推出的购物网站,有生存空间吗?:https://www.ikjzd.com/home/102704
口述:老公两次出轨现在下跪求我原谅:http://lady.shaoqun.com/a/273803.html
贤惠老婆在公司过于开放:http://lady.shaoqun.com/m/a/271908.html

没有评论:

发表评论