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

相关文章
|
5天前
|
SQL 缓存 Java
|
18天前
|
XML Java 数据库连接
探秘MyBatis:手写Mapper代理的源码解析与实现
探秘MyBatis:手写Mapper代理的源码解析与实现
21 1
|
18天前
|
SQL Java 数据库连接
深度解析MyBatis核心:探寻其核心对象的精妙设计
深度解析MyBatis核心:探寻其核心对象的精妙设计
22 1
深度解析MyBatis核心:探寻其核心对象的精妙设计
|
18天前
|
SQL Java 数据库连接
深入源码:解密MyBatis数据源设计的精妙机制
深入源码:解密MyBatis数据源设计的精妙机制
31 1
深入源码:解密MyBatis数据源设计的精妙机制
|
2月前
|
Java 数据库连接 mybatis
mybatis简单案例源码详细【注释全面】——Utils层(MybatisUtils.java)
mybatis简单案例源码详细【注释全面】——Utils层(MybatisUtils.java)
13 0
|
2月前
|
Java 数据库连接 mybatis
mybatis简单案例源码详细【注释全面】——测试层(UserMapperTest.java)
mybatis简单案例源码详细【注释全面】——测试层(UserMapperTest.java)
10 0
|
2月前
|
Java 数据库连接 mybatis
mybatis简单案例源码详细【注释全面】——Dao层映射文件(UserMapper.xml)【重要】
mybatis简单案例源码详细【注释全面】——Dao层映射文件(UserMapper.xml)【重要】
10 0
|
2月前
|
Java 数据库连接 mybatis
mybatis简单案例源码详细【注释全面】——Dao层接口(UserMapper.java)
mybatis简单案例源码详细【注释全面】——Dao层接口(UserMapper.java)
7 0
|
2月前
|
SQL Java 数据库连接
挺详细的spring+springmvc+mybatis配置整合|含源代码
挺详细的spring+springmvc+mybatis配置整合|含源代码
45 1
|
2月前
|
druid Java 数据库连接
Spring Boot3整合MyBatis Plus
Spring Boot3整合MyBatis Plus
46 1