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

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

关于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,那么也就不会进入对于数据库的查询了。开启了二级缓存之后,就不需要进行对数据库的查询了。


网络异常,图片无法展示
|

目录
相关文章
|
3月前
|
存储 缓存 芯片
让星星⭐月亮告诉你,当我们在说CPU一级缓存二级缓存三级缓存的时候,我们到底在说什么?
本文介绍了CPU缓存的基本概念和作用,以及不同级别的缓存(L1、L2、L3)的特点和工作原理。CPU缓存是CPU内部的存储器,用于存储RAM中的数据和指令副本,以提高数据访问速度,减少CPU与RAM之间的速度差异。L1缓存位于处理器内部,速度最快;L2缓存容量更大,但速度稍慢;L3缓存容量最大,由所有CPU内核共享。文章还对比了DRAM和SRAM两种内存类型,解释了它们在计算机系统中的应用。
115 1
|
4月前
|
缓存 Java 数据库连接
mybatis复习05,mybatis的缓存机制(一级缓存和二级缓存及第三方缓存)
文章介绍了MyBatis的缓存机制,包括一级缓存和二级缓存的配置和使用,以及如何整合第三方缓存EHCache。详细解释了一级缓存的生命周期、二级缓存的开启条件和配置属性,以及如何通过ehcache.xml配置文件和logback.xml日志配置文件来实现EHCache的整合。
mybatis复习05,mybatis的缓存机制(一级缓存和二级缓存及第三方缓存)
|
4月前
|
SQL XML Java
mybatis-源码深入分析(一)
mybatis-源码深入分析(一)
|
2月前
|
SQL Java 数据库连接
Mybatis架构原理和机制,图文详解版,超详细!
MyBatis 是 Java 生态中非常著名的一款 ORM 框架,在一线互联网大厂中应用广泛,Mybatis已经成为了一个必会框架。本文详细解析了MyBatis的架构原理与机制,帮助读者全面提升对MyBatis的理解和应用能力。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Mybatis架构原理和机制,图文详解版,超详细!
|
29天前
|
缓存 Java 数据库连接
MyBatis缓存机制
MyBatis提供两级缓存机制:一级缓存(Local Cache)默认开启,作用范围为SqlSession,重复查询时直接从缓存读取;二级缓存(Second Level Cache)需手动开启,作用于Mapper级别,支持跨SqlSession共享数据,减少数据库访问,提升性能。
32 1
|
1月前
|
缓存 Java 数据库连接
深入探讨:Spring与MyBatis中的连接池与缓存机制
Spring 与 MyBatis 提供了强大的连接池和缓存机制,通过合理配置和使用这些机制,可以显著提升应用的性能和可扩展性。连接池通过复用数据库连接减少了连接创建和销毁的开销,而 MyBatis 的一级缓存和二级缓存则通过缓存查询结果减少了数据库访问次数。在实际应用中,结合具体的业务需求和系统架构,优化连接池和缓存的配置,是提升系统性能的重要手段。
53 4
|
2月前
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
2月前
|
SQL 缓存 Java
MyBatis如何关闭一级缓存(分注解和xml两种方式)
MyBatis如何关闭一级缓存(分注解和xml两种方式)
86 5
|
3月前
|
缓存 Java 数据库连接
使用MyBatis缓存的简单案例
MyBatis 是一种流行的持久层框架,支持自定义 SQL 执行、映射及复杂查询。本文介绍了如何在 Spring Boot 项目中集成 MyBatis 并实现一级和二级缓存,以提高查询性能,减少数据库访问。通过具体的电商系统案例,详细讲解了项目搭建、缓存配置、实体类创建、Mapper 编写、Service 层实现及缓存测试等步骤。
|
3月前
|
缓存 NoSQL Ubuntu
大数据-39 Redis 高并发分布式缓存 Ubuntu源码编译安装 云服务器 启动并测试 redis-server redis-cli
大数据-39 Redis 高并发分布式缓存 Ubuntu源码编译安装 云服务器 启动并测试 redis-server redis-cli
66 3