2.一级缓存本质是什么?一级缓存什么时候被创建?一级缓存的工作流程?

利用MyBatis自身本地缓存结合Redis实现分布式缓存 一、Redis分布式缓存的实现 1、什么是缓存? 计算机内存中的一段数据。 2、内存中数据特点 读写快 断电立即丢失 3、缓存解决了什么问题? 提高网站吞吐量(请求响应)提高, 网站运行效率快 缓存的存在是用来解决数据库访问压力 4、既然缓存能提高效率, 所有项目中都加缓存吗? 使用缓存时一定是数据库中数据极少发生修改, 更多用于查询情况, 比如地址, 省, 市, 等 5、本地缓存和分布式缓存的区别? 本地缓存 : 存在应用服务器内存中数据称之为本地缓存(Local Cache) 分布式缓 阅读详情

MyBatis一级缓存

问题:
1.一级缓存到底是什么?
2.一级缓存什么时候被创建?
3.一级缓存的工作流程是怎样的?

源码分析流程

一级缓存到底是什么?解答

由于一级缓存与SqlSession有关下面分析从SqlSession接口方法入手
1.找到SqlSession中与缓存相关的方法-clearCache();
2.进入SqlSessoin实现类DefaultSqlSession,发现实现clearCache()的代码是

private final Executor executor;
public void clearCache() {
 this.executor.clearLocalCache();
 }

3.进入 Executor的实现类BaseExecutor实现clearLocalCache();的代码是

protected PerpetualCache localCache;
protected PerpetualCache localOutputParameterCache;
public void clearLocalCache() {
        if (!this.closed) {
            this.localCache.clear();
            this.localOutputParameterCache.clear();
        }

    }

3.进入PerpetualCache类clear();发现执行的是Map的clear方法;

 private Map<Object, Object> cache = new HashMap();
public void clear() {
        this.cache.clear();
    }

4.由此发现问题一中一级缓存是什么的答案是:一级缓存就是一个Map集合,一个SqlSession中有一个。

一级缓存什么时候被创建?一级缓存的工作流程是怎样的?解答

一级缓存应该是在首次查询时候创建
1.进入Sqsession的实现类DefaultSqlSession中selectList(String statement, Object parameter, RowBounds rowBounds);底层调用了SQL执行器Executor的query方法。

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        List var5;
        try {
            MappedStatement ms = this.configuration.getMappedStatement(statement);
            var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
        } catch (Exception var9) {
            throw ExceptionFactory.wrapException("Error querying database.  Cause: " + var9, var9);
        } finally {
            ErrorContext.instance().reset();
        }
  1. Executor的实现类BaseExecutor实现query方法,发现CacheKey与createCacheKey方法,
    又源码得知CacheKey由MappedStatement(mapper映射封装实体类) +parameter(入参)+RowBounds (分页参数)构成;
Override 
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
 BoundSql boundSql = ms.getBoundSql(parameter);
  //创建缓存 
  CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
   return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
 public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
        if (this.closed) {
            throw new ExecutorException("Executor was closed.");
        } else {
        
            CacheKey cacheKey = new CacheKey();
            //MappedStatement 的 id 
        // id就是Sql语句的所在位置包名+类名+ SQL名称
            cacheKey.update(ms.getId());
            // offset 就是 从索引为0的第一条数据开始取 , limit 0,Integer.MAXVALUE
            cacheKey.update(rowBounds.getOffset());
            // limit 就是 Integer.MAXVALUE,从索引为0的第一条数据开始取Integer.MAXVALUE条数据
            cacheKey.update(rowBounds.getLimit());
            //具体的SQL语句
            cacheKey.update(boundSql.getSql());
            List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
            TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
            Iterator var8 = parameterMappings.iterator();

            while(var8.hasNext()) {
                ParameterMapping parameterMapping = (ParameterMapping)var8.next();
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    String propertyName = parameterMapping.getProperty();
                    Object value;
                    if (boundSql.hasAdditionalParameter(propertyName)) {
                        value = boundSql.getAdditionalParameter(propertyName);
                    } else if (parameterObject == null) {
                        value = null;
                    } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                        value = parameterObject;
                    } else {
                        MetaObject metaObject = this.configuration.newMetaObject(parameterObject);
                        value = metaObject.getValue(propertyName);
                    }
					//后面是update 了 sql中带的参数
                    cacheKey.update(value);
                }
            }

            if (this.configuration.getEnvironment() != null) {
                cacheKey.update(this.configuration.getEnvironment().getId());
            }

            return cacheKey;
        }
    }

3.然后进入BaseExecutor的this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);查询部分

//一级缓存
protected PerpetualCache localCache;
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
        if (this.closed) {
            throw new ExecutorException("Executor was closed.");
        } else {
            if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
                this.clearLocalCache();
            }

            List list;
            try {
                ++this.queryStack;
                // 缓存中获取
                list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
                if (list != null) {
                //如果存在封装结果直接返回
                    this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
                } else {
                //如果没有再去查询
                    list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
                }
            } finally {
                --this.queryStack;
            }

            if (this.queryStack == 0) {
                Iterator var8 = this.deferredLoads.iterator();

                while(var8.hasNext()) {
                    BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next();
                    deferredLoad.load();
                }

                this.deferredLoads.clear();
                if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                    this.clearLocalCache();
                }
            }

            return list;
        }
    }
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);

        List list;
        try {
        //查询获取最新的值
            list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
        //情况原有缓存
            this.localCache.removeObject(key);
        }
		// 更新最新缓存结果值
        this.localCache.putObject(key, list);
        if (ms.getStatementType() == StatementType.CALLABLE) {
            this.localOutputParameterCache.putObject(key, parameter);
        }

        return list;
    }

4.解决了问题一级缓存是什么时候创建的:一级缓存实在第一次查询时创建的。
解决了问题一级缓存的工作流程是什么:第一次查询时后创建,第二次查询的时候会先去缓存中查询是否存在不存在则再次查询,并将查询结果放入缓存,如果存在则直接返回。

雪莉果的Axure原型工厂vol.006 中继器应用(二)——多选穿梭框 如果你用axure有一段时间了,那么你很快就能琢磨出一个大体设计流程,比如加一个中间过度的元件,来储存需要穿梭的内容;但是如果你再想一想,就会发现,这样做,似乎只能解决单选,那么多选需要怎么操作呢? 这时候,中继器就会告诉你,我还能做的更多。 阅读详情

相关推荐

Coding Plan:程序员真实工作的可执行编码决策框架

Coding Plan 是一种面向工程实践的编码决策方法论,它超越传统学习路径,聚焦于代码在真实业务系统中的上下文对齐、影响控制与可演进性保障。其核心在于将模糊的开发直觉转化为可度量、可验证、可协作的日常动作,涵盖目标对齐、上下文锁定、验证闭环、协作契约和演进预留五大锚点。结合2026年AI辅助编码新范式,它强调将大模型作为‘上下文翻译器’而非代码生成器,并通过分钟级工作块、技术债主动发行、可观测性前置等机制,显著提升交付确定性与系统长期健康度。本文详解该框架的底层逻辑与落地实践。

weixin_33326218的博客 436

Mybatis整合redis

1、首先导入maven依赖: 版本: 依赖包: 2、接下来配置redis:可以写在spring配置文件中,也可以分开写,分开写需要 &lt;import resource="classpath:redis.xml"/&gt;引入到spring中 2.1 创建一个redis.properties文件,只要是用来写连接池的配置 #ip地址 redis.hostName=127....

qq_42335943的博客 403

ArcGIS利用模型构建器批量导出nc文件中的不同波段数据

ArcGIS利用模型构建器批量导出nc文件中的不同波段数据

Yuanbaokk的博客 7252

mybatis与redis整合

redis与ehcache都是专业的缓存框架,redis与mybatis的整合方式与ehcache类似,不同的是,redis需要先搭建自己的redis服务,用来存放缓存数据。 这里主要演示mybatis与redis的整合过程,redis服务的搭建可以参考 Java连接redis简单demo示例,这里使用本地的Windows环境的redis服务,与mybatis进行整合。 1、添加redis依赖...

蜗牛学习笔记 8390

海康威视SADP SDK实战:5分钟搞定局域网设备搜索(附C++代码示例)

本文详细解析了海康威视SADP SDK在局域网设备搜索中的高效应用,通过C++代码示例展示如何快速实现设备发现与信息获取。SADP协议支持全面设备信息采集和实时状态更新,适用于智能安防和物联网管理场景,帮助开发者5分钟内完成设备搜索功能集成。

rum55的博客 871

嵌入式状态机编程-QP状态机框架与常见状态机方法

状态机基本术语 现态:是指当前所处的状态。 条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。 动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。 次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。 传统有限状态机Fsm实现方法 如图,是一个定时计数器,计数器存在两种状态,一种为设置状态,一种为计时状态 设

qq_36969440的博客 9661

mybatis整合redis

mybatis整合redis步骤 1.添加redis相关依赖           redis与spring的整合依赖           log4j2配置:Log4j2 + Slf4j            jackson     2.spring + redis 集成实现缓存功能(与mybatis无关)           添加两个redis的配置文件,并将redis.properties和s...

Soul717的博客 1781

手把手教你学 AI芯片 SOC软件开发专栏简介

在AI芯片(如NPU、GPU加速器)爆发式增长的今天,软件栈开发已成为AI应用落地的核心瓶颈。无论是模型推理加速、低延迟部署,还是能效优化,都依赖于对芯片底层软件的深度掌握。然而,许多开发者困于“只会调用API,不懂驱动实现”的困境,导致性能瓶颈难以突破。本专栏《手把手教你学 AI芯片 SOC软件开发》专为AI工程师、嵌入式开发者及系统架构师打造,从零基础切入,系统拆解AI芯片SOC(System on Chip)的完整软件栈,覆盖Runtime(运行时)

MHD0815的博客 168

mybatis集成redis

4. WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。3. SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。1. LRU – 最近最少使用的:移除最长时间不被使用的对象。2. FIFO – 先进先出:按对象进入缓存的顺序来移除它们。1,在同一namespace下。......

随风飘絮 452

“华为杯”研究生数学建模竞赛2020年-【华为杯】D题:无人机集群协同对抗(附获奖论文和MATLAB代码实现)

1.问题重述摘 要:本文针对非线性约束条件下红蓝双方无人机集群协同对抗的最优规划问题,结合贪婪队形、非线性规划、内点法、蒙特卡洛方法和全联立正交配置有限元法,构建了无人机集群协同对抗推演模型。,构建了。我们综合考虑了,和。首先分析红方在集群约束下的贪婪队形和拦截策略,然后我们基于内点法联合MATLAB和AMPL编程求解蓝方突防的非线性规划解,最后基于蒙特卡洛法对整个蓝方突防过程进行推演,得到突防概率图。通过推演,我们提出了两块的区域作为所求区域,并对蓝方的最优突防策略进行分析。

getusushu的博客 1550

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Mybatis一级缓存和二级缓存

缓存可以将数据保存在内存中,是互联网系统常常用到的。目前流行的缓存服务器有 MongoDB、Redis、Ehcache 等。缓存是在计算机内存上保存的数据,读取时无需再从磁盘读入,因此具备快速读取和使用的特点。和大多数持久化框架一样,MyBatis 提供了一级缓存和二级缓存的支持。默认情况下,MyBatis 只开启一级缓存。mybatis的的一级缓存是SqlSession级别的缓存,一级缓存缓存的是对象,当SqlSession提交、关闭以及其他的更新数据库的操作发生后,一级缓存就会清空。

qq_53123736的博客 6897

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

MyBatis 一级缓存与二级缓存

MyBatis 提供两级缓存机制提升查询性能:一级缓存:SqlSession 级别,默认开启二级缓存:Mapper 级别,需手动开启 两者协同工作,形成查询数据优先级:二级缓存 → 一级缓存 → 数据库作用域:单个 SqlSession(数据库会话)生命周期:随 SqlSession 创建而创建随 SqlSession 关闭或清空()而销毁存储位置:内存中的 HashMap(非序列化)默认状态:开启状态,无需配置 2. 工作流程 三、二级缓存(Second Level Cache) 1. 核心特性

qq_62112907的博客 3197

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Mybatis一级缓存

Mybatis一个SqlSession对象中创建一个本地缓存localCache,在二级缓存不命中情况下,对于每一次查询,都会尝试去本地缓存中查找当前查询Sql的结果数据,如果在缓存中,就直接从缓存中取出,然后返回给用户;否则,从数据库读取数据,将查询结果存入缓存并返回给用户。Mybatis查询数据顺序:二级缓存 ---> 一级缓存 ---> 数据库一级缓存是SQLSession级别的,每一个SqlSession会创建一个一级缓存,两个不同的SqlSession执行同一个查询Sql也是查询各自的一级缓存。

kandroid的博客 2333

Mybatis一级缓存和二级缓存原理区别(图文详解)

Java面试经常问到Mybatis一级缓存和二级缓存,今天就给大家重点详解Mybatis一级缓存和二级缓存原理与区别@mikechen

mikechen的互联网架构 1万+

MyBatis实战(5)缓存机制(一级缓存、二级缓存)

这篇博客对Mybatis中的一级缓存和二级缓存做了比较详细的阐述,并有完整的代码实现。

扬帆向海的博客 4220

Hibernate一级缓存和二级缓存详解

一、一级缓存二级缓存的概念解释 (1)一级缓存就是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中,如果短时间内这个 session(一定要同一个session)又做了同一个操作,那么hibernate直接从一级缓存中拿,而不会再去连数据库,取数据。 (2)二级缓存就是SessionFactory级别的缓存,顾名思义,就是查询的时候会把查询结果

徐刘根的博客 2万+

Mybatis一级缓存和二级缓存分别是什么,区别是什么?

二级缓存的作用域为SqlSessionFactory,是一个映射器级别的缓存,针对不同namespace的映射器。一个会话中,查询一条数据,这个数据会被放到一级缓存中,但是一旦这个会话关闭,一级缓存汇总的数据就会被保存到二级缓存。在同一个SqlSession中,执行相同的sql语句,那么第一次就会去数据库中进行查询,并写到缓存中,如果我们后面还想去访问数据库查询,就直接去一级缓存中获取就可以了。mybatis的的一级缓存是SqlSession级别的缓存,一级缓存缓存的是对象,当SqlSession提。

qq_59510147的博客 3793

MyBatis缓存实战指南:一级与二级缓存的深度解析与性能优化

在电商大促期间,我们的用户查询接口QPS从500骤增至5000,数据库连接池频频告警。当我将MyBatis二级缓存应用在用户基础信息模块后,数据库负载直接下降70%——这就是缓存的力量。

DD2187718660的博客 2739

【全网最全】mybatis一定要禁用一级二级缓存

mybatis源码设计非常优秀,然后阅读源码又必须跨域一道门槛:缓存,虽然mybatis的缓存已经不再适用现在的技术框架,但是仍有很多需要注意的地方。

liangcheng0523的博客 1万+

详解mybatis一级缓存以及工作流程

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录系列文章目录前言一、pandas是什么?二、使用步骤1.引入库2.读入数据总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是本篇文章正文内容,下面案例

L4937的博客 1403

深入解析 MyBatis 缓存:一级缓存与二级缓存实战指南

MyBatis通过两级缓存机制提升数据库访问性能:一级缓存作用于SqlSession级别,默认开启,适合同一会话内重复查询优化;二级缓存作用于Mapper级别,需手动配置,支持跨会话共享数据。两者核心差异在于作用域和共享范围,分别适用于不同场景:一级缓存用于事务内重复查询,二级缓存适合全局配置和热点数据。合理使用缓存可显著减少数据库访问,但需注意缓存失效机制和潜在的数据一致性问题。

cyf123__的博客 1446

Mybatis一级缓存详解

Mybatis一级缓存详解

汤键的博客 1963

MyBatis-一级缓存与二级缓存

前言 MyBatis是一个简单,小巧但功能非常强大的ORM开源框架,它的功能强大也体现在它的缓存机制上。 每当我们使用MyBatis开启一次和数据库的会话,MyBatis会创建出一个SqlSession对象表示一次数据库会话。 在对数据库的一次会话中,我们有可能会反复地执行完全相同的查询语句,如果不采取一些措施的话,每一次查询都会查询一次数据库,而我们在极短的时间内做了完全相同的查询,那么它们的结果极有可能完全相同,由于查询一次数据库的代价很大,这有可能造成很大的资源浪费。 为了解决这一问题,减少资源的浪费

杨晓尚 2626

Mybatis的一级缓存与二级缓存

此时我们发现,这里只有一条sql查询语句,说明第一次是通过数据库查询到的信息,而第二次没有查询数据库,直接就显示了信息,说明信息是从缓存获得的。3.一级缓存的生命周期和SlSession的生命周期相同,SalSession对象关闭,一级缓存也会关闭。1.一级缓存底层使用的是Map集合,key存储的是执行的SQL语句,value存放的是查询的对象。查询的时候,先从SqlSession的缓存中查找,如果有,直接返回。1.二级缓存是全局缓存,范围跨越多个SqlSession,可以再不同的Mapper之间共享。

m0_62923286的博客 986

MyBatis缓存机制:一级与二级缓存详解

一级缓存与二级缓存的原理与实战 MyBatis提供两级缓存优化查询性能:一级缓存为SqlSession级别,默认开启,仅在单次会话内有效;二级缓存为Mapper级别,需手动配置,支持跨会话共享。一级缓存通过LocalCache实现,写操作会自动清空;二级缓存要求实体类序列化,通过Cache接口实现,写操作会清空当前Mapper缓存。本文详细分析了两级缓存的工作原理、配置方法、使用场景及优化技巧,包括缓存失效场景、序列化要求、分布式缓存集成方案等,帮助开发者合理运用缓存提升系统

2401_83675559的博客 1360
上一篇: 为什么不建议调用sun.*包中的方法,Reflection.getCallerClass()报错
下一篇: 4.<cache>标签解析剖析
躺平程序猿
博客等级 码龄8年 4870粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

躺平程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值