MyBatis一级和二级缓存

MyBatis的一级、二级缓存 一级缓存是 MyBatis 内部的缓存,作用范围是SqlSession。每个SqlSession都有自己的一级缓存,当在同一个SqlSession中执行多次查询时,MyBatis 会将查询结果缓存在SqlSession的一级缓存中。若再次执行相同的查询操作,MyBatis 会直接从缓存中获取数据,而不再访问数据库。二级缓存是 MyBatis 提供的全局缓存,作用范围是Mapper 映射文件。它可以跨多个SqlSession存储数据,通常用于多个请求或多个用户之间共享缓存。一级缓存。 阅读详情

一级缓存创建时机

/**
 * DefaultSqlSessionFactory#openSession
 */
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
  Transaction tx = null;
  try {
    final Environment environment = configuration.getEnvironment();
    final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
    tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
    // 创建Executor执行器
    final Executor executor = configuration.newExecutor(tx, execType);
    // 创建DefaultSqlSession
    return new DefaultSqlSession(configuration, executor, autoCommit);
  } catch (Exception e) {
    closeTransaction(tx); // may have fetched a connection so lets call close()
    throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}

创建SqlSession时调用了这个方法创建了DefaultSqlSession,创建Executor执行器会生成一级缓存

/**
 * Configuration#newExecutor
 */
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
	executorType = executorType == null ? defaultExecutorType : executorType;
	executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
	Executor executor;
	if (ExecutorType.BATCH == executorType) {
		// 批处理执行器
		executor = new BatchExecutor(this, transaction);
	} else if (ExecutorType.REUSE == executorType) {
		// 可重用执行器
		executor = new ReuseExecutor(this, transaction);
	} else {
		// 简单执行器
		executor = new SimpleExecutor(this, transaction);
	}
	// 如果开启二级缓存(默认是开启的),则使用缓存执行器
	if (cacheEnabled) {
		executor = new CachingExecutor(executor);
	}
	// 执行插件
	executor = (Executor) interceptorChain.pluginAll(executor);
	return executor;
}

如果开启了二级缓存(二级缓存的全局开关,默认是开启的),会把执行器包装成缓存执行器CachingExecutor,但真正执行操作的还是BatchExecutor、ReuseExecutor、SimpleExecutor

protected BaseExecutor(Configuration configuration, Transaction transaction) {
  this.transaction = transaction;
  this.deferredLoads = new ConcurrentLinkedQueue<>();
  // 一级缓存
  this.localCache = new PerpetualCache("LocalCache");
  this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");
  this.closed = false;
  this.configuration = configuration;
  this.wrapper = this;
}

BatchExecutor、ReuseExecutor、SimpleExecutor都继承了BaseExecutor类,所以在创建时会调用父类构造器,这时会创建一级缓存。一级缓存就是BaseExecutor的localCache属性,所以也无法关闭一级缓存。

二级缓存创建时机

/**
 * MapperAnnotationBuilder#parse
 */
public void parse() {
  // 获取mapper接口的全路径
  String resource = type.toString();
  // 是否解析过该mapper接口
  if (!configuration.isResourceLoaded(resource)) {
    // 先解析mapper映射文件
    loadXmlResource();
    // 设置解析标识
    configuration.addLoadedResource(resource);
    // Mapper构建者助手
    assistant.setCurrentNamespace(type.getName());
    // 解析CacheNamespace注解
    parseCache();
    // 解析CacheNamespaceRef注解
    parseCacheRef();
    Method[] methods = type.getMethods();
    for (Method method : methods) {
      try {
        // issue #237
        if (!method.isBridge()) {
      	  // 每个mapper接口中的方法,都解析成MappedStatement对象
          parseStatement(method);
        }
      } catch (IncompleteElementException e) {
        configuration.addIncompleteMethod(new MethodResolver(this, method));
      }
    }
  }
  parsePendingMethods();
}

在解析Mapper接口时,如果有CacheNamespace或者CacheNamespaceRef注解的话会创建二级缓存。CacheNamespace是创建自己的缓存,CacheNamespaceRef是指向其他Mapper接口的缓存。

缓存使用

/**
 * CachingExecutor#query
 */
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
    throws SQLException {
  // 获取二级缓存
  Cache cache = ms.getCache();
  if (cache != null) {
    // 刷新二级缓存
    flushCacheIfRequired(ms);
    if (ms.isUseCache() && resultHandler == null) {
      ensureNoOutParams(ms, boundSql);
      // 从二级缓存中查询数据
      @SuppressWarnings("unchecked")
      List<E> list = (List<E>) tcm.getObject(cache, key);
      // 如果二级缓存中没有查询到数据,则查询数据库
      if (list == null) {
        // 委托给BaseExecutor执行
        list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
        // 放入二级缓存
        tcm.putObject(cache, key, list); // issue #578 and #116
      }
      return list;
    }
  }
  // 委托给BaseExecutor执行
  return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}

在查询时,如果开启了二级缓存(默认是开启的),执行器也就是CachingExecutor,会先去二级缓存中查询,有数据就直接返回;如果没有二级缓存,或者二级缓存查询不到,就委托真实的执行器查询

/**
 * BaseExecutor#query
 */
@Override
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 (closed) {
    throw new ExecutorException("Executor was closed.");
  }
  if (queryStack == 0 && ms.isFlushCacheRequired()) {
    clearLocalCache();
  }
  List<E> list;
  try {
    queryStack++;
    // 从一级缓存中获取数据
    list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
    if (list != null) {
      handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
    } else {
  	  // 如果一级缓存没有数据,则从数据库查询数据,并且存入一级缓存
      list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
    }
  } finally {
    queryStack--;
  }
  if (queryStack == 0) {
    for (DeferredLoad deferredLoad : deferredLoads) {
      deferredLoad.load();
    }
    // issue #601
    deferredLoads.clear();
    if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
      // issue #482
      clearLocalCache();
    }
  }
  return list;
}

所以,Mybatis查询顺序:二级缓存 → 一级缓存 → 数据库。

根据源码可以发现,一级缓存是SqlSession级别,二级缓存是Mapper接口级别的。一级缓存是没办法关闭;二级缓存关闭可以把全局开关cacheEnabled设置成 false,或者Mapper接口不加CacheNamespace或者CacheNamespaceRef注解

MyBatis 批量插入(ExecutorType.BATCH) 一、在mybatis中ExecutorType的使用 1.Mybatis内置的ExecutorType有3种,默认的是simple,该模式下它为每个语句的执行创建一个新的预处理语句,单条提交sql;而batch模式重复使用已经预处理的语句, 并且批量执行所有更新语句,显然batch性能将更优; 2.但batch模式也有自己的问题,比如在Insert操作时,在事务没有提交之前,是没有办法获取到自增的id,这在某型情形下是不符合业务要求的; 在测试中使用simple模式提交10000条数据,时间为18248 毫 阅读详情

相关推荐

mybatis的一级缓存和二级缓存

一、什么是缓存 缓存是存在于内存中的临时数据。 使用缓存减少和数据库的交互次数,提高执行效率。 1、适用于缓存 经常查询并且不经常改变的; 数据的正确与否对最终结果影响不大的; 2、不适用于缓存 经常改变的数据; 数据的正确与否对最终结果影响很大的; 例如:商品的库存,银行的汇率,股市的牌价; 二、mybatis一级缓存 1、一级缓存简介 一级缓存作用域是sqlsession级别的,同一个sqlsession中执行相同的sql查询(相同的sql和参数),第一次会去查询数据库并写到缓存中,第

学Java,找哪吒 7万+

mybatis批量插入优化(ExecutorType.BATCH/BatchInsert/executeBatch)

Mybatis内置的有3种,默认的是simple单句模式,该模式下它为每个语句的执行创建一个新的预处理语句,单句提交sql;batch模式重复使用已经预处理的语句,并且批量执行所有语句,大批量模式下性能更优。请注意batch模式在Insert操作时事务没有提交之前,是没有办法获取到自增的id,所以请根据业务情况使用。使用simple模式提交10000条数据,时间为19s,batch模式为6s ,大致情况如此,优化的具体还要看提交的语句情况。如果需要使用foreach。

★【World Of Moshow 郑锴】★ 3万+

在Mac上搭建本地AI工作流:Dify与DeepSeek的完美结合

本文介绍了在Mac上搭建本地AI工作流的方法,结合Dify平台和DeepSeek模型。Dify是一个开源的大语言模型应用开发平台,支持可视化AI应用开发。部署步骤包括:1)安装Homebrew和Docker;2)克隆Dify代码库;3)配置环境变量并启动服务。同时,使用Ollama工具本地部署DeepSeek模型,将其集成到Dify中创建聊天助手。通过配置模型接口和新建应用,用户可以在本地环境中实现AI对话功能。这种方案既保证了数据隐私,又提供了灵活的AI应用开发能力。

Linda的自动化测试之旅 1535

mybatis使用ExecutorType.BATCH方式批量插入数据

2.mapper.xml文件,我这里是写的是插入或更新语句,数据库是oracle,所以用merge into这种写法,判断条件,如果流水号存在,则更新,否则插入,mysql则是insert on duplicate key update 那种写法,如果这里不需要插入或更新,那就写普通的insert语句就可以了.有从excel中导入大量数据到数据库这种需求,如果一条一条insert就会很慢,mybatis默认是ExecutorType.SIMPLE方式.3.经过测试,导入五千条数据,几秒钟就可以插入完成.

zhangbeihai8的博客 3571

《计算机网络》复试问答题总结

DNS 是一个联机分布式数据库系统,负责主机名和 IP 地址之间的转换,需要进行域名查询的机器主动发起域名解析请求,域名服务器则随时准备做出响应。域名服务器的数据库中存放着它所管辖范围的主机名和 IP 地址之间的映射表,域名服务器之间又可以相互联络和协作,以便分布在 Internet 各个域名服务器数据库中的域名都能被有效地搜索,从而实现主机名与 IP 地址的映射。为了提高解析效率,使用了域名缓存技术。在服务器、主机中设置一个专用的内存缓冲区。服务器用来存放近期解析过的域名及其对应的 IP 地址的映射。

weixin_45971154的博客 2027

arduino esp8266_Arduino传感器教程 第22章ESP8266 控制 5V 继电器

ESP8266控制5V继电器目录一、NodeMCU二、工作原理本文将使用亚马逊 AlexaEcho 和 ESP8266 控制 5V 继电器。NodeMCUNodeMCU 是一个开源的 IoT 物联网硬件开发板,由于它支持 WIFI 功能且使用方法十分类似 Arduino 开发板,所以近些年获得了越来越多来自全世界的创客朋友们的青睐。NodeMCU 尺寸与 Arduino Nano 类似。...

weixin_39611722的博客 3455

Mybatis批处理ExecutorType.BATCH

我们改为用原生的Batch插入,这样子的话,只要500多毫秒,也就是0.5秒的样子。通过批处理的方式,我们就可以在 JDBC 客户端缓存多条 SQL 语句,然后在 flush 或缓存满的时候,将多条 SQL 语句打包发送到数据库执行,这样就可以有效地降低上述两方面的损耗,从而提高系统性能。每次向数据库发送的 SQL 语句的条数是有上限的,如果批量执行的时候超过这个上限值,数据库就会抛出异常,拒绝执行这一批 SQL 语句,所以我们需要控制批量发送 SQL 语句的条数和频率。

qq_28865843的博客 2227

SC8F073单片机串口通信保姆级教程:从寄存器配置到完整收发Demo(附避坑指南)

本文详细解析了SC8F073单片机串口通信的寄存器配置与调试技巧,涵盖TXSTA、RCSTA和SPBRG寄存器的逐位设置,提供精确的波特率计算方法和工业级抗干扰策略。通过完整的收发Demo和避坑指南,帮助开发者快速掌握底层串口通信技术,适用于工业控制等严苛环境。

weixin_33724046的博客 484

Mybatis批处理踩坑,纠正网上的一些错误写法

这篇文章会一步一步带你从一个新手的角度慢慢揭开批处理的神秘面纱,对于初次写Mybatis批处理的同学可能会有很大的帮助,建议收藏点赞~

Linn的博客 3131

体素坐标(voxel_coors)在mmdetection3d中的理解

体素坐标(voxel_coors)在mmdetection3d中的理解

weixin_38362784的博客 4217

三种方法教你下载大模型到本地,总有一种适合你

本文主要介绍了下载大模型到本地的三种解决方案,希望能对同学们有所帮助。 文章目录 1. 场景/问题描述 2. 方案一:使用git 3. 方案二:镜像站 4. 方案三:高速下载工具(变体及自定义代码) 4.1 aria2 4.2 自定义代码

weixin_43178406的博客 17万+

mybatis中一级缓存和二级缓存

1.一级缓存 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。 Mybatis默认开启一级缓存。 一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执...

流的博客 2万+

指纹浏览器指纹工厂(下):基于真实设备数据特征的马尔可夫链生成与校验

本文揭示了静态指纹生成算法在高级风控时序追踪下的致命缺陷,指出违背设备演进马尔可夫性质(如无状态跳跃、因果断裂)是导致指纹存活率骤降的核心原因。通过分析风控系统的时序状态机与多维特征验证机制,提出基于隐马尔可夫模型(HMM)的动态指纹架构:以真实设备的状态转移链为蓝本,构建异步演进的“数字基因熔炉”,通过非均匀时间步长、突发事件响应及微观因果绑定,模拟软硬件独立更新的物理法则。最终实现指纹在时间维度与微观特征上的自洽,规避风控的时序陷阱。

数据知道的博客 415

Mybatis一级缓存和二级缓存

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

qq_53123736的博客 6897

【温室气体数据集】全球总碳柱观测网络 TCCON

【温室气体数据集】全球总碳柱观测网络 TCCON

WW、forever的博客 436

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

mybatis的一级、二级缓存

mybatis的一级缓存和二级缓存 mybatis 的一级缓存:sqlsession 级别的,内部维护的其实就是Map,其缓存对象是PerpetualCache。 1、MyBatis的一级缓存是SqlSession级别的,但是它并不定义在SqlSessio接口的实现类DefaultSqlSession中,而是定义在DefaultSqlSession的成员变量Executor中,Exe...

cuichunchi的博客 6826

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

MyBatis一级缓存和二级缓存全面详解

一级缓存的内容不能跨sqlsession。由MyBatis自动维护。,缓存范围比一级缓存更大。不同的sqlsession可以访问二级缓存的内容。哪些数据放入二级缓存需要自己指定。

2401_87299389的博客 2940

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

MyBatis 的一级缓存和二级缓存

文章目录一、前言二、一级缓存三、二级缓存3.1、开启二级缓存:四、测试一下五、总结: 一、前言 先说缓存,合理使用缓存是优化中最常见的,将从数据库中查询出来的数据放入缓存中,下次使用时不必从数据库查询,而是直接从缓存中读取,避免频繁操作数据库,减轻数据库的压力,同时提高系统性能。 二、一级缓存 一级缓存 是 SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有...

猎人在吃肉 7776

Mybatis一级缓存与二级缓存

mybatis的有两种缓存,一级缓存和二级缓存。两个缓存的不同点和相同点总结如下 不同点: 一级缓存存在于一个SqlSession之内,二级缓存存在于不同的SqlSession之间 一级缓存不需要手动开启,属于默认开启状态;二级缓存需要手动开启 相同点: 在增删改SQL之后,缓存会自动清空 flushCache="true"的查询语句查询内容不存放进缓存   一级缓存 一级缓存是my...

蜗牛学习笔记 3912

mybatis缓存详解,一级缓存和二级缓存举例讲解

mybatis缓存详解,一级缓存和二级缓存举例讲解

相关项目可以查看https://gitee.com/fan-pl或https://github.com/fpl1116 2276

【MyBatis】MyBatis的一级缓存和二级缓存简介

二级缓存是基于 mapper文件的namespace的,也就是说多个sqlSession可以共享一个mapper中的二级缓存区域,并且如果两个mapper的namespace相同,即使是两个mapper,那么这两个mapper中执行sql查询到的数据也将存在相同的二级缓存区域中。这是因为spring整合Mybatis之后,sqlSession是要交给spring容器去管理的,在每一次执行sql之后,spring会将sqlSession关闭,关闭sqlSession会清空一级缓存,所以一级缓存就会失效。

小七的博客 1510

MyBatis框架一级、二级缓存

MyBatis 提供的一级缓存和二级缓存机制为开发者在构建高性能应用时提供了有力的工具。一级缓存是 SQLSession 级别的缓存,默认开启且不需要额外配置,适用于单个事务内多次相同查询的场景。二级缓存是 Mapper 级别的缓存,需要显式配置,适用于跨事务、频繁访问相同数据的场景。然而,缓存的使用也有其局限性,特别是在数据一致性和实时性要求较高的场景下,可能需要权衡缓存的优势与潜在的问题。

Flying_Fish_roe的博客 1736

MyBatis 的一级缓存与二级缓存

一、简述 MyBatis 的一级缓存是基于数据库会话(SqlSession 对象)的,默认开启。二级缓存是基于全局(nameSpace)的,开启需要配置。 对于 JDBC 操作,如果需要连续请求 id=1 的用户数据,那么就要进行两次的数据库连接,获取数据库中的数据。相同的数据,进行两次数据库连接,这肯定会造成资源的浪费。基于面向对象,可以把第一次获取的数据保存到一个对象中,下一次直接从对象中获取就行了,如图: 获取的内容保存在对象中,在一个请求期间,直接使用或者传递对象就可以了。对于 JDBC 的操作,

ChineseSoftware的博客 1万+

mybatis的一级二级缓存详解及源码解剖

一级缓存是指在同一个SqlSession中,对于相同的查询语句和参数,第一次查询的结果会被缓存到内存中,后续的查询会直接从缓存中获取结果,而不会再次查询数据库。一级缓存是MyBatis默认开启的,可以通过在SqlSession中调用clearCache()方法来清空缓存。二级缓存是指在多个SqlSession中,对于相同的查询语句和参数,第一次查询的结果会被缓存到内存中,后续的查询会直接从缓存中获取结果,而不会再次查询数据库。二级缓存是需要手动开启的,可以通过在Mapper.xml文件中添加标签来开启。

qq_48157004的博客 3004
上一篇: Spring循环依赖问题
下一篇: 缓存淘汰——LRU和LFU算法
我还能卷
博客等级 码龄4年 22粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值