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

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


前言

一: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对象。

相关文章
|
2月前
|
Java 数据库连接 数据库
mybatis查询数据,返回的对象少了一个字段
mybatis查询数据,返回的对象少了一个字段
192 8
|
2月前
|
SQL XML Java
mybatis-源码深入分析(一)
mybatis-源码深入分析(一)
|
1月前
|
前端开发 Java 数据库连接
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
本文是一份全面的表白墙/留言墙项目教程,使用SpringBoot + MyBatis技术栈和MySQL数据库开发,涵盖了项目前后端开发、数据库配置、代码实现和运行的详细步骤。
51 0
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
|
1月前
|
Java 数据库连接 mybatis
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
该文档详细介绍了如何在Springboot Web项目中整合Mybatis,包括添加依赖、使用`@MapperScan`注解配置包扫描路径等步骤。若未使用`@MapperScan`,系统会自动扫描加了`@Mapper`注解的接口;若使用了`@MapperScan`,则按指定路径扫描。文档还深入分析了相关源码,解释了不同情况下的扫描逻辑与优先级,帮助理解Mybatis在Springboot项目中的自动配置机制。
136 0
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
|
3月前
|
Web App开发 前端开发 关系型数据库
基于SpringBoot+Vue+Redis+Mybatis的商城购物系统 【系统实现+系统源码+答辩PPT】
这篇文章介绍了一个基于SpringBoot+Vue+Redis+Mybatis技术栈开发的商城购物系统,包括系统功能、页面展示、前后端项目结构和核心代码,以及如何获取系统源码和答辩PPT的方法。
|
1月前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
118 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
1月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
56 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
1月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
351 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
|
1月前
|
SQL Java 数据库连接
mybatis使用二:springboot 整合 mybatis,创建开发环境
这篇文章介绍了如何在SpringBoot项目中整合Mybatis和MybatisGenerator,包括添加依赖、配置数据源、修改启动主类、编写Java代码,以及使用Postman进行接口测试。
17 0
mybatis使用二:springboot 整合 mybatis,创建开发环境
|
1月前
|
Java 数据库连接 API
springBoot:后端解决跨域&Mybatis-Plus&SwaggerUI&代码生成器 (四)
本文介绍了后端解决跨域问题的方法及Mybatis-Plus的配置与使用。首先通过创建`CorsConfig`类并设置相关参数来实现跨域请求处理。接着,详细描述了如何引入Mybatis-Plus插件,包括配置`MybatisPlusConfig`类、定义Mapper接口以及Service层。此外,还展示了如何配置分页查询功能,并引入SwaggerUI进行API文档生成。最后,提供了代码生成器的配置示例,帮助快速生成项目所需的基础代码。
下一篇
无影云桌面