IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 13.MyBatis缓存机制 -> 正文阅读

[大数据]13.MyBatis缓存机制

13.MyBatis缓存机制

1. 为什么使用缓存?

当用户频繁查询某些固定的数据时,第一次将这些数据从数据库中查询出来,保存在缓存中。当用户再次查询这些数据时,不用再通过数据库查询,而是去缓存里面查询。减少网络连接和数据库查询带来的损耗,从而提高我们的查询效率,减少高并发访问带来的系统性能问题。

一句话概括:经常查询一些不经常发生变化的数据,使用缓存来提高查询效率。

像大多数的持久化框架一样,Mybatis也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。 Mybatis中缓存分为一级缓存,二级缓存。

2.一级缓存

一级缓存是SqlSession级别的缓存,是默认开启的。

  • 所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。

image-20220224140450719

2.1 验证

 /**
     * 根据id查询用户
     * @throws IOException
     */
    @Test
    public void test8() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.findUserById(1);
        System.out.println(user);
        User user1 = userMapper.findUserById(1);
        System.out.println(user);

        sqlSession.close();
    }

我们可以发现,虽然在上面的代码中我们查询了两次,但最后只执行了一次数据库操作,这就是Mybatis提供给我们的一级缓存在起作用了。因为一级缓存的存在,导致第二次查询id为1的记录时,并没有发出sql语句从数据库中查询数据,而是从一级缓存中查询。结果如图所示:

image-20220224142956506

2.2 分析

  • 一级缓存是SqlSession范围的缓存,执行SqlSession的C(增加)U(更新)D(删除)操作,或者调用clearCache()、commit()、close()方法,都会清空缓存。

image-20220224142436863

  1. 第一次查询用户id为1的用户信息,先去缓存中查找id为1的用户信息,如果没有,从数据库查询用户信息。
  2. 得到用户信息,将用户信息存储到一级缓存中(sqlSession缓存区域)
  3. 如果执行SqlSession的C(增加)U(更新)D(删除)操作,或者调用clearCache()、commit()、close()方法,都会清除缓存。如果没有清除缓存,在同一个sqlSession对象调用同一个Mapper方法,会去一级缓存中查找之前查找过的数据,而不用去数据库重新查找。

2.3清除缓存

sqlSession.clearCache();

 @Test
    public void test8() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.findUserById(1);
        System.out.println(user);
        //手动清除缓存
        sqlSession.clearCache();
        User user1 = userMapper.findUserById(1);
        System.out.println(user);

        sqlSession.close();
    }

此时回执行两遍sql,结果如图:

image-20220224142836920

此外也可以在xml映射文件,设置每次执行都会清除缓存。

<!-- 每次查询时,都会清除缓存 -->
< select flushCache="true"></select>

3.二级缓存

3.1二级缓存介绍

  1. 二级缓存是namespace级别(跨sqlsession)的缓存,是默认不开启的。
  2. 二级缓存的开启需要进配置,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的,也就是实现Serializable接口。
  3. 只需要在映射XML文件配置,就可以开启二级缓存。

image-20220224154808603

3.2验证

(1)配置核心配置文件

<settings>
  <!--
因为cacheEnabled的取值默认就为true,所以这一步可以省略不配置。
为true代表开启二级缓存;为false代表不开启二级缓存。
  -->
  <setting name="cacheEnabled" value="true"/>
</settings>

(2)配置UserMapper.xml映射

<mapper namespace="com.lagou.dao.UserMapper">
  <!--当前映射文件开启二级缓存-->
  <cache></cache>
  <!--
<select>标签中设置useCache=true”代表当前这个statement要使用二级缓存。
如果不使用二级缓存可以设置为false
    注意:
      针对每次查询都需要最新的数据sql,要设置成useCache="false",禁用二级缓存。
-->
  <select id="findById" parameterType="int" resultType="user" useCache="true"
>
   SELECT * FROM `user` where id = #{id}
  </select>
</mapper>

(3)修改实体类

public class User implements Serializable {
  private Integer id;
  private String username;
  private Date birthday;
  private String sex;
  private String address;
 
  private List<Role> roleList;
  private List<Order> orderList;
}

(4)测试结果

@Test
public void testTwoCache() throws Exception {
  SqlSession sqlSession = MyBatisUtils.openSession();
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  User user = userMapper.findById(41);
  System.out.println("第一次查询的用户:" + user);
  sqlSession.close();
  SqlSession sqlSession1 = MyBatisUtils.openSession();
  UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
  User user1 = userMapper1.findById(41);
  System.out.println("第二次查询的用户:"+user1);
  sqlSession1.close();
}

3.3二级缓存分析

  • 二级缓存是跨级别的缓存,多个sqlsession去操作同一个Mapper映射的sql语句,多个sqlsession可以共用二级缓存(是跨sqlsession的)。

    image-20220224155653993

引入二级缓存会带来的问题

  • mybatis的二级缓存因为是namespace级别,所以在进行多表查询时会产生脏读问题

image-20220224155401563

需求:查询用户信息及用户关联的订单信息金额(关联两张表user、order表)

分析:

  1. 第一次查询出用户信息的金额:199元
  2. 第二次查询,会在二级缓存区域获得数据,金额依然为:199元
  3. 现在去更新order表用户所对应的订单金额,修改为:299元
  4. 现在就出现非常严重的脏读问题!!!
    1. 因为去修改order表的数据,是操作orderMapper.xml,所以只清除的是orderMapper.xml的缓存。UserMapper.xml的缓存依然存在,所以脏数据依然存在。
  • 实际开发会使用第三方缓存,例如rides.

4.小结

  1. mybatis的缓存,都不需要我们手动存储和获取数据。mybatis自动维护的。
  2. mybatis开启了二级缓存后,那么查询顺序:二级缓存–》一级缓存–》数据库
  3. 注意:mybatis的二级缓存会存在脏读问题,需要使用第三方的缓存技术解决问题。
  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-02-26 11:37:32  更:2022-02-26 11:38:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 12:11:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码