Mybatis源码剖析 一级缓存和二级缓存的底层原理

4 篇文章 0 订阅

关于mybatis里面的一级缓存:
mybatis里面的一级缓存和二级缓存实际上和hibernate里面的差别不大。
一级缓存其实通俗地来讲就是,在sqlsession里面创建一个本地缓存,然后第二次进行相同的查询时候,就不会到数据库里面进行查找。
关于一级缓存我们不得不提及的内容就是这个类了:
PerpetualCache

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.cache.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;

public class PerpetualCache implements Cache {
    private final String id;
    private Map<Object, Object> cache = new HashMap();

    public PerpetualCache(String id) {
        this.id = id;
    }

    public String getId() {
        return this.id;
    }

    public int getSize() {
        return this.cache.size();
    }

    public void putObject(Object key, Object value) {
        this.cache.put(key, value);
    }

    public Object getObject(Object key) {
        return this.cache.get(key);
    }

    public Object removeObject(Object key) {
        return this.cache.remove(key);
    }

    public void clear() {
        this.cache.clear();
    }

    public ReadWriteLock getReadWriteLock() {
        return null;
    }

    public boolean equals(Object o) {
        if (this.getId() == null) {
            throw new CacheException("Cache instances require an ID.");
        } else if (this == o) {
            return true;
        } else if (!(o instanceof Cache)) {
            return false;
        } else {
            Cache otherCache = (Cache)o;
            return this.getId().equals(otherCache.getId());
        }
    }

    public int hashCode() {
        if (this.getId() == null) {
            throw new CacheException("Cache instances require an ID.");
        } else {
            return this.getId().hashCode();
        }
    }
}

是的,这个类里面主要的核心就是一个hashmap。
举个例子来说,当我们查询一遍数据库内容的时候,它会存储相应的内容到cache
这个哈希表中,截图如下所示:
这里写图片描述
假若再要深入探索:
可以发现相应的一个内容:
BaseExecutor.queryFromDatabase()函数,这个函数是一个在debug中非常实用的一个函数。
假若当我们需要查看mybatis的sql语句时候,而mybatis有没有采用打印sql的方式在控制台输出,那么我们就可以使用断点停留的方式来查看sql内容了。
这里写图片描述
现在我们来进行一次小实验:
假设我们进行一次sql的查询,就会发现以下内容:
首先是第一次查询:
会往perpetualCache里面存放相应的数据缓存信息:
这里写图片描述
在一次次的翻看源码的时候,渐渐发现mybatis里面有个非常有趣的东西,叫做
mappedStatements,这个类里面主要用于处理xml映射的内容,里面的id正好是我们xml里面定义的内容:
这里写图片描述
通过对于源码的再次深入,我们会发现里面的BaseExecutor.createCacheKey
类,在这个类里面有创建缓存的核心代码部分内容:
这里写图片描述
在经过多次的断点查询之后,终于终于在BaseExecutor里面的public List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException 这个函数中看到了关键点:
第一次查询的时候会将查询的内容存入localCache里面
这里写图片描述
第二次查询的时候会直接从里面取出
这里写图片描述
一级缓存使用sqlsession作为单位划分的。
每次查询会先去缓存中找,如果找不到,再去数据库查询,然后把结果写到缓存中。Mybatis的内部缓存使用一个HashMap,key为hashcode+statementId+sql语句。Value为查询出来的结果集映射成的java对象。
SqlSession执行insert、update、delete等操作commit后会清空该SQLSession缓存。

关于二级缓存

在二级缓存里面,我们需要开启以下的配置内容:
这里写图片描述
在setting里面开启二级缓存的作用域是针对于全局性的。
如果只是想要单独对于某一个sql的二级缓存查询开启,我们可以在相应的select标签里面设置:
这里写图片描述
同时还要添加一个cache配置:
这里写图片描述
查询的model需要进行序列化操作:
这里写图片描述
当我们开启了二级缓存以后,通过断点的方式进入到源码里面查看就会发现相应的内容:
这里写图片描述
之前没有开启二级缓存的时候,这里的cache是个null值,但是由于xml里的配置开启了二级缓存,所以这个时候程序会用putobject来进行一个缓存存储。
第二次查询相同内容的时候,我们通过断点可以看到源码里面的内容:
由于第一次进行sql查询的时候,mybatis做了相应的操作设置:

this.tcm.putObject(cache, key, list);

Mybatis的key为:
这里写图片描述
Value则是查询出来的内容和信息,因此这里面的list不为null,那么也就不会进入对于数据库的查询了。开启了二级缓存之后,就不需要进行对数据库的查询了。
这里写图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值