Mybatis源码细节探究:MappedStatement和Cache对象对照关系研究

news2024/11/28 5:34:12

给自己的每日一句

不从恶人的计谋,不站罪人的道路,不坐亵慢人的座位,惟喜爱耶和华的律法,昼夜思想,这人便为有福!他要像一棵树栽在溪水旁,按时候结果子,叶子也不枯干。凡他所做的尽都顺利

本文内容整理自《孙哥说Mybatis系列课程》

前言

在这里插入图片描述

一:Mapper.xml被读取发生的事

1:Mapper.xml文件中一个标签会对应一个MappedStatement对象,那么没一个查询Select标签也是对应一个MappedStatement
2:Cache对象是基于Mapper.xml文件中的Cache标签创建。一个Cache标签只能创建出来一个Cache对象
结论就是一个Cache对象会被多个MS对象引用,属于一对多的关系。

细节分析

一:缓存内部就是PerpetualCache

PerpetualCache本质上就是个Hashmap,上边两个Select标签标签查询出来的数据都会缓存到这个Map缓存的数据当中。

二:缓存key

Cache中的key被封装成了CacheKey这样的一个对象。

1:key的构成

那什么玩意作为key呢?value这个玩意就存在于List当红在哪个就好了,那么key呢?

key的构成规则大概就是:integer + namespace.id + SQL + 参数 大体上是这么个玩意构成

2:真实key举例

-976698875:6380909722:com.baizhiedu.dao.UserDAO.queryAllUsers:0:2147483647:select id,name from t_user:default

通过这里我们可以知道,基于CacheKey也是能够实现拿到拼接SQL的一种方式,有了对应的SQL和参数,我们可以手动拼接SQL

在这里插入图片描述

3:什么时候入缓存?

按照上述的两个SQL语句执行完毕,并且事务提交之后,HashMap当中会有两条缓存数据

4:资源占用问题

一个Select标签对应的MP对象都会存储Cache,这样不是很占用内存资源么?
只是引用,Cache对象只有一个。

证明MappedStatement和Cache对象的多对一关系

一个十分重要的细节:必须事务提交之后,才能把Cache放入到缓存当中。

    @Test
    public void test2() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        SqlSession sqlSession3 = sqlSessionFactory.openSession();


        UserDAO userDAO1 = sqlSession1.getMapper(UserDAO.class);
        UserDAO userDAO2 = sqlSession2.getMapper(UserDAO.class);
        UserDAO userDAO3 = sqlSession3.getMapper(UserDAO.class);

       /* List<User> users1 = userDAO1.queryAllUsersByPage();//--- ms ---> cache

        for (User user : users1) {
            System.out.println("user = " + user);
        }*/

        User user1 = userDAO1.queryUserById(4); //---ms ---> cache

        sqlSession1.commit();

        //userDAO1.queryAllUsers();

        System.out.println("-----------------------------------------");

        /*List<User> users2 = userDAO2.queryAllUsersByPage();

        for (User user : users2) {
            System.out.println("user = " + user);
        }*/

        sqlSession2.commit();

        System.out.println("-----------------------------------------");
//
 /*       User user = new User(4, "xiaowb");
        userDAO3.update(user);

        sqlSession3.commit();*/

    }

重点关注这行代码

        User user1 = userDAO1.queryUserById(4); //---ms ---> cache
        sqlSession1.commit();

sqlSession1.commit();执行后才会放到缓存当中。
在这个位置上边的代码走过ms.getCache的时候,Cache对象size是0;

通过debug来证明的,不同的MappedStatement对应的Cache对象是一个。

自问自答

一:不同的Mapper文件查询标签缓存数据能不能放到一个Cache当中呢?

可以

在这里插入图片描述
这样做的目的就是:引用别的Mapper文件中的Cache来存储数据。

二:使用缓存后脏数据怎么办?

所谓脏数据就是对UseDao做更新操作,Mybatis对缓存数据是怎么处理的?

更新操作包括,update,delete,insert,Mybatis会将Mapper对应Cache对象当中所有的key以及对应的内容都清空!也就是Mapper所有缓存数据都干掉!

clear()操作根源是发生在TransactionalCache当中,这Cache的一个装饰器。他的作用就是事务执行完毕之后,完成一些操作,事务完成之后才会写入内存

如果是增删改操作,一定是事务提交的时候,会走将事务清空

 public void commit() {
    if (clearOnCommit) {
      delegate.clear();//删除操作
    }
    flushPendingEntries();//方缓存操作
    reset();//中间对象清楚操作。
  }

  private void flushPendingEntries() {
    for (Map.Entry<Object, Object> entry : entriesToAddOnCommit.entrySet()) {
      delegate.putObject(entry.getKey(), entry.getValue());
    }
    for (Object entry : entriesMissedInCache) {
      if (!entriesToAddOnCommit.containsKey(entry)) {
        delegate.putObject(entry, null);
      }
    }
  }

这个TransactionalCache的装饰器是非常好的,只要有增删改,Mapper对应的Cache数据全部被删除,避免脏数据。

在这里插入图片描述

关联查询怎么避免缓存脏数据?

关联查询怎么玩呢?也是往缓存中楞塞,但是有这样的一个问题,我们在UserDao.XML当中使用缓存,这样更新User数据会清空Cache。

但是如果有User和Order的关联查询,那么情空Order需要在使用Cache-ref标签的情况下才会出现,更新order数据会刷新User当中Cache标签的问题,因为ref标签会导致两个Mapper.xml用的是一个Cache对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/590504.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《面试1v1》类加载过程

我是 javapub&#xff0c;一名 Markdown 程序员从&#x1f468;‍&#x1f4bb;&#xff0c;八股文种子选手。 面试官&#xff1a; 你了解Java的类加载过程吗?跟我聊聊classes是如何加载到JVM中的。 候选人&#xff1a; Java的类加载过程由加载、验证、准备、解析和初始化5个…

5月底了,现在不想着跳槽可就晚了

前两天跟朋友感慨&#xff0c;今年的铜三铁四、裁员、疫情导致好多人都没拿到offer!现在已经5月底了&#xff0c;具体金九银十只剩下三个月。 对于想跳槽的职场人来说&#xff0c;绝对要从现在开始做准备了。这时候&#xff0c;很多高薪技术岗、管理岗的缺口和市场需求也出来了…

五、常用提升物体的方式

机器人在运动中伸展和提升功能&#xff0c;历来是比赛中机器人的一个重要的性能指标&#xff0c;因为按 比赛要求&#xff0c;机器人在上场前必须经过体积大小的检测&#xff0c;而在场地中如果能够有更好的伸展性 能将对比赛成绩十分有利&#xff0c;因此机器人提升自身高度以…

SAP-MM发票校验容差详解

MIRO发票校验容差详解 MIRO发票校验容差是指收货业务与发票校验业务之间的差异&#xff0c;这种差异可 能是物料价格差异、收货数量差异、收货金额差异等等&#xff0c;总之&#xff0c;发票校验的容差 内容最为丰富&#xff0c;容差类型有很多种&#xff0c;如下表所示&…

【ChatGPT插件第一期】28个ChatGPT插件,让你的学习、工作、生活效率翻倍!

文章目录 人工智能福利文章什么是ChatGPT插件如何使用ChatGPT插件28个插件全解读写在最后 人工智能福利文章 【分享几个国内免费可用的ChatGPT镜像】【10几个类ChatGPT国内AI大模型】【用《文心一言》1分钟写一篇博客简直yyds】【用讯飞星火大模型1分钟写一个精美的PPT】 Cha…

Linux I2C驱动分析4 - GPIO模拟I2C

一. 前言 在嵌入式开发中&#xff0c;由于芯片的I2C接口有限&#xff0c;或者出于硬件画板的方便&#xff0c;我们都需要将普通的GPIO模拟I2C接口使用。出于对这样的需求&#xff0c;Linux-2.6.x已经有相关代码了&#xff0c;Linux-3.x有标准的内核选项支持该功能&#xff0c;内…

模特信息管理系统的开发与实现(ASP.NET,SQLServer)

需求分析 模特信息管理系统主要给商家和模特用户提供服务&#xff0c;系统分为前台和后台两部分。 本研究课题重点主要包括&#xff1a;活动管理&#xff0c;商家管理&#xff0c;模特管理&#xff0c;系统公告管理和活动报名管理。 活动管理模块主要实现活动更新、活动添加、活…

生鲜农产品冷链物流配送路径优化模型构建及算法实现

摘要&#xff1a;本案例讲述的案例为生鲜农产品冷链物流配送路径优化&#xff0c;涉及的目标函数成本包括碳排放成本、固定成本、运输成本、货损变质成本、时间惩罚成本。 目标种类&#xff1a;单目标模型。 求解方法&#xff1a;基础版蚁群算法改进版蚁群算法。 整体对标层…

快速掌握EasyExcel在web场景中的应用(读和写)

目录 一、引入依赖 二、设置表头 三、web下载模板 四、测试下载功能 五、复杂表头 六、写入数据 七、格式优化 7.1 日期自定义转换 7.2 列宽行高注解 八、动态表头 九、动态表格写入数据 一、引入依赖 <dependency><groupId>com.alibaba</groupId>…

Linux——生产者消费者模型和信号量

目录​​​​​​​ 基于BlockingQueue的生产者消费者模型 概念 条件变量的第二个参数的作用 锁的作用 生产者消费者模型的高效性 生产者而言&#xff0c;向blockqueue里面放置任务 消费者而言&#xff0c;从blockqueue里面拿取任务&#xff1a; 总结 完整代码(不含存储…

从零开始搭建一个moveit2简单机械臂模型

文章目录 前言一、设计一个简单机械臂二、构造创建文件关系CMakeLists.txt 修改增加如下&#xff1a;package.xml 修改增加如下&#xff1a;urdf.rviz 全文如下&#xff1a;demo.launch.py 全文如下&#xff1a; launch rviz构造link构造joint 总结 前言 在网上搜了许多文章&a…

游戏互动,用Python点燃【儿童节】的欢乐!

当孩子们踏入人生的旅途时&#xff0c;他们需要的并不仅仅是学习知识&#xff0c;更需要的是在快乐的氛围中成长。六一儿童节即将来临&#xff0c;让我们用Python代码为孩子们送去一份特别的礼物吧&#xff01; 在本篇文章中&#xff0c;我会带领大家一起探索如何利用Python代…

php中文字符串提取方法,preg_replace 和preg_match_all区别

在php中&#xff0c;可以利用以下两种函数来只提取字符串的中文字符 preg_replace()函数 preg_match_all()函数 方法1&#xff1a;使用preg_match_all()函数 preg_match_all()函数配合正则表达式“/[\x{4e00}-\x{9fff}]/u”可以过滤字符串&#xff0c;只获取中文字符。 会…

chatgpt赋能python:Python中[:3]的用法介绍

Python中[:3]的用法介绍 Python是一种高级编程语言&#xff0c;经常被用于数据科学、机器学习、人工智能和Web应用程序开发。在Python中&#xff0c;有许多有用的编程技巧和语法&#xff0c;其中之一就是[:3]。 什么是[:3]&#xff1f; 在Python中&#xff0c;[:3]是一种称为…

研发工程师玩转Kubernetes——使用Ingress进行路由

依据微服务理念&#xff0c;我们希望每个独立的功能由一个服务支持。比如有两个接口&#xff1a;http://www.xxx.com/plus和http://www.xxx.com/minus&#xff0c;前者由一个叫plus-service的服务支持&#xff0c;后者由一个叫minus-service的服务支持。这样就需要一个路由层&a…

华为OD机试真题B卷 Java 实现【查找两个字符串a,b中的最长公共子串】,附详细解题思路

一、题目描述 查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个。 注:子串的定义:将一个字符串删去前缀和后缀(也可以不删)形成的字符串。请和“子序列”的概念分开! 数据范围:字符串长度1≤length≤300 。 二、输入描述 输入两个字符串…

牛客网刷题学习SQL(五)

SQL25 查找山东大学或者性别为男生的信息 分析&#xff1a; 查看学校为山东大学或者性别为男性的用户的device_id、gender、age和gpa数据&#xff0c;结果不去重。 山东大学 --》 where university“山东大学” 男性—》where gender “male” 结果不去重 所以上面不能使用or&…

改进的yolo目标检测(yolo创新与改进)

目标检测是计算机视觉领域中的一个重要问题,它需要从图像或视频中检测出物体的位置和类别。近年来,深度学习技术在目标检测领域取得了显著的进展,其中一个重要的方法是基于YOLO(You Only Look Once)算法的目标检测。 YOLO算法的优点是速度快,但是在检测小物体和密集物体…

SAP-MM-发票-采购附加成本处理简介

一&#xff0e;采购附加成本处理&#xff1a; 原材料的采购成本包括采购成本&#xff08;采购单价*采购数量&#xff09;和相关采购附加成本&#xff08;运输费、保险费、报关费、仓储费、滞期费、租船费、码头费及代理费等费用&#xff09;&#xff0c;对于采购附加成本主要有…

覆盖标准(白盒、黑盒和灰盒)

覆盖标准(白盒、黑盒和灰盒) 覆盖标准Coverage Criteria 覆盖标准采用软件的抽象表示并将其划分为可测试的功能。 每个功能构成了测试需求的基础——需要由软件的测试套件进行测试的东西。 当测试套件的一个测试用例满足测试要求时&#xff0c;我们说测试要求被覆盖。测试套件…