mybatis的一级缓存使用以及禁用

news2025/1/19 11:23:48

目录

验证代码如下

mappper 代码

xml 中代码

实际执行代码

执行结果

DefaultSqlSession

CachingExecutor

BaseExecutor

PerpetualCache

总结

禁用一级缓存

mapper 对应的 xml 的 select 查询设置 flushCache 属性为 true

MappedStatement 的内部类 Builder 向外部变量 flushCacheRequired 赋值

MapperBuilderAssistant 的 setStatementCache()

XMLStatementBuilder 的 parseStatementNode() 解析 mapper 中定义的 sql

mybatis 全局配置 settings 中添加 name 为 localCacheScope 的节点,对应 value 为 STATEMENT

XMLConfigBuilder的settingsElement()方法

有一个问题,为什么每次创建 SqlSession 缓存就不能共用了?


在之前的文章基础上

https://blog.csdn.net/zlpzlpzyd/article/details/135171524

验证代码如下

mappper 代码

package cn.hahaou.mybatis.cache.levelone.mapper;

import cn.hahaou.mybatis.cache.levelone.entity.Role;

public interface LevelOneRoleMapper {

    Role getRole(Long id);
}

xml 中代码

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.hahaou.mybatis.cache.levelone.mapper.LevelOneRoleMapper">

    <resultMap id="roleMap" type="role">
        <id column="id" property="id" javaType="long" jdbcType="BIGINT"></id>
        <result column="role_name" property="roleName" javaType="string" jdbcType="VARCHAR"></result>
        <result column="note" property="note"></result>
    </resultMap>

    <select id="getRole" parameterType="long" resultType="role">
        select * from t_role t where t.id = #{id}
    </select>
</mapper>

实际执行代码

package cn.hahaou.mybatis.cache.levelone;

import cn.hahaou.mybatis.cache.levelone.mapper.LevelOneRoleMapper;
import cn.hahaou.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

/**
 * 一级缓存测试
 */
public class LevelOneCacheTest {

    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtils.openSession();
        LevelOneRoleMapper roleMapper = sqlSession.getMapper(LevelOneRoleMapper.class);
        roleMapper.getRole(1L);
        System.out.println("使用同一个SqlSession再执行一次");
        roleMapper.getRole(1L);
        sqlSession.close();
    }
}

执行结果

2023-12-23 19:30:56,109 [main] DEBUG org.apache.ibatis.logging.LogFactory: Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
2023-12-23 19:30:56,204 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
2023-12-23 19:30:56,206 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
2023-12-23 19:30:56,206 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
2023-12-23 19:30:56,206 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource: PooledDataSource forcefully closed/removed all connections.
2023-12-23 19:31:15,482 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction: Opening JDBC Connection
2023-12-23 19:31:15,943 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource: Created connection 439928219.
2023-12-23 19:31:15,943 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction: Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1a38c59b]
2023-12-23 19:31:15,953 [main] DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==>  Preparing: select * from t_role t where t.id = ? 
2023-12-23 19:31:16,082 [main] DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters: 1(Long)
2023-12-23 19:31:16,187 [main] DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger: <==      Total: 1
使用同一个SqlSession再执行一次
2023-12-23 19:32:41,371 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction: Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1a38c59b]
2023-12-23 19:32:41,378 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction: Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1a38c59b]
2023-12-23 19:32:41,379 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource: Returned connection 439928219 to pool.

可以看到,最终查询只执行了一次。

在之前的获取 SqlSession 的基础上,有一个地方

这里的 Executor 是在  Configuration 中获取的,这里需要一个参数 ExecutorType,看看调用这里的地方是怎么传参的。

可知,默认是取的  Configuration 的 defaultExecutorType 的值,再到 Configuration 看一下。

由源码得知,Configuration 中 ExecutorType 的值默认为 SIMPLE

 回到刚才创建的地方,最终返回的结果为 CachingExecutor,通过责任链模式的方式包装了 SimpleExecutor。

Executor的实现类

DefaultSqlSession

调用了 mapper 中的方法后,触发反射操作进入 MapperProxy 的 invoke()

鉴于当前查询是单值操作,走查询单条数据逻辑

MapperMethod 中有两个类型的变量 SqlCommand 和 MethodSignature。

SqlCommand 里面有两个变量

name 保存了当前访问的 mapper 方法。

type 对应 mapper 里的 sql 标签定义的各种 sql 操作类型,即 dml 操作

MethodSignature

对应 mapper 里的 sql 标签里的各个属性设置

 

通过 Configuration 获取 MappedStatement 对象。

MappedStatement 中 sqlSource 的类型是 RawSqlSource,通过责任链模式的方式内嵌了 StaticSqlSource,最终的 sql 在变量 sql 里。

调用 CachingExecutor 的 query()

CachingExecutor

在这里有两件事,创建 CacheKey 和调用嵌套的 SimpleExecutor 执行查询。其中 CacheKey 用于接下来缓存查询结果使用。

BaseExecutor

SimpleExecutor 是 BaseExecutor 的子类。CachingExecutor 中调用了 createCacheKey() 实际上调用了 CacheKey 的 createCacheKey()。

其中主要通过 update() 向里面的集合变量添加数据。具体信息如下

第1个为 MappedStatement 的 id,即需要查询的方法全路径
第2个为 RowBounds 的 offset,默认值为 0
第3个为 RowBounds 的 limit,默认值为 Integer.MAX_VALUE
第4个为 BoundSql 的 sql
第5个为查询的参数值
第6个为 Environment 信息,在配置中指定

定义了一个全局变量 localCache 缓存查询结果

首次查询没有数据,调用 queryFromDatabase() 从数据库中查询。否则,直接从缓存中获取数据。

 查询结束后将 CacheKey 和对应的结果分为作为键值对保存到 localCache 中。

PerpetualCache

数据最终存储到了 map 对象中。

总结

可以看到,通过一个简单的查询,mybatis 使用了责任链模式,通过内存缓存当前查询结果,但是这个只适用于那种单体应用,分布式应用的话使用一级缓存不太好,有缓存不一致的问题。

如果数据量大的话会造成内存溢出的情况发生。

所以,针对项目部署的是集群环境,不要用一级缓存。如果是单体数据量不大可以使用。

禁用一级缓存

可知,有两种方式

mapper 对应的 xml 的 select 查询设置 flushCache 属性为 true

<select flushCache="true" id="getRole" parameterType="long" resultType="role">
	select * from t_role t where t.id = #{id}
</select>

MappedStatement 的内部类 Builder 向外部变量 flushCacheRequired 赋值

MapperBuilderAssistant 的 setStatementCache()

setStatementCache() 的上层调用方法 addMappedStatement()

XMLStatementBuilder 的 parseStatementNode() 解析 mapper 中定义的 sql

可以看到,如果 SqlCommandType 值为 SELECT,flushCache 的值的情况如下

如果 flushCache 的值未设置,flushCache 值为 false,默认使用缓存。

如果 flushCache 的值设置为 true,flushCache 值为 true,禁止使用缓存。

mybatis 全局配置 settings 中添加 name 为 localCacheScope 的节点,对应 value 为 STATEMENT

<setting name="localCacheScope" value="STATEMENT"/>

其中 localCacheScope 实际对应的是枚举类型 LocalCacheScope,只有两个值,默认值为 SESSION。

XMLConfigBuilder的settingsElement()方法

package org.apache.ibatis.session;

/**
 * @author Eduardo Macarron
 */
public enum LocalCacheScope {
  SESSION,STATEMENT
}

如果指定了其他值,创建 SqlSessionFactory 的过程中会出现异常。

这两种方式,要讲哪种方式好,还是全局方式好,当然,对于一级缓存禁用的情况需要按照实际情况来。

有一个问题,为什么每次创建 SqlSession 缓存就不能共用了?

因为每次在调用 SqlSessionFactory 的 openSession() 都会创建 Executor 实例,但是 BaseExecutor 是 SimpleExecutor 的父类,CachingExecutor 通过责任链模式包装了 SimpleExecutor,所以,新建了 SqlSession 就不能使用之前的缓存了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1331067.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

parseInt(0.0000005)大于等于5

文章目录 一、前言二、parseInt()的神秘行为三、解决parseInt()的奥秘四、结论五、最后 一、前言 parseInt() 是 JavaScript 的内置函数&#xff0c;用于解析数字字符串中的整数。例如&#xff0c;从数字字符串中解析整数100&#xff1a; const number parseInt(100); numbe…

Netty-3-封帧

实际上&#xff0c;数据的封帧与解帧本身虽然实现起来十分简单&#xff0c;但它们在本质上仍然是数据的一种编解码。 那么它们相比之前介绍的数据编解码有什么区别呢&#xff1f;单从编码目标看&#xff0c;之前介绍的数据编解码是为了对用户的数据对象进行传输。 封帧与解帧则…

【Linux】编辑、查看和搜索文件

大多数 Linux 发行版不包含真正的 vi;而是自带一款高级替代版本&#xff0c;叫做 vim(它是“vi improved”的简写)由 Bram Moolenaar 开发的&#xff0c;vim 相对于传统的 Unix vi 来说&#xff0c;取得了实质性进步。 启动和退出 vim 使用vim可以启动&#xff0c;如命令行输…

MyBatis 通过 SqlSession 实现动态Entity批量插入

需要几个关键点: 1、entity对应的service需要继承BaseService 2、entity对应的serviceImpl需要实现baseMapper方法&#xff0c;需要把当前的mapper返回去 3、entity对应的Mapper需要BaseMapper

快速安装方式安装开源OpenSIPS和CP控制界面

OpenSIPS是目前世界上主流的两个SIP软交换引擎(其中另外一个是kamailio)或者SIP信令服务器&#xff08;个人认为是比较正确的称谓&#xff09;。关于Opensips的基础和一些参数配置和安装方式笔者在很久以前的历史文档中有非常多的介绍。最近&#xff0c;很多用户使用OpenSIPS软…

PHP案例代码:PHP如何提供下载功能?

对Web开发人员来说,“下载”功能是一个非常常见的需求。在网站中提供文件下载,通常用于提供用户手册、软件升级、音乐、视频等各种资源文件。本教程将向您介绍如何实现一个PHP下载功能,同时告诉浏览器文件名称、文件大小、文件类型,并统计下载次数。 首先,我们需要了解一些…

蓝牙物联网在智能家居中的应用前景

物联网智能家居系统是应用物联网技术&#xff0c;在传统家居环境下将各种零散无序的电器整合成统一整体&#xff0c;实现家电的全程自动控制&#xff0c;满足用户高效管理需求的一种新型家居模式。 其主要的子系统有家居感知系统、家庭网络系统、智能家居控制管理系统等&#x…

Hadoop入门学习笔记——七、Hive语法

视频课程地址&#xff1a;https://www.bilibili.com/video/BV1WY4y197g7 课程资料链接&#xff1a;https://pan.baidu.com/s/15KpnWeKpvExpKmOC8xjmtQ?pwd5ay8 Hadoop入门学习笔记&#xff08;汇总&#xff09; 目录 七、Hive语法7.1. 数据库相关操作7.1.1. 创建数据库7.1.2…

Python之zip函数相关介绍

python3的zip函数 zip函数接受任意多个可迭代对象作为参数&#xff0c;将对象中对应的元素打包成一个tuple&#xff0c;然后返回一个可迭代的zip对象。 这个可迭代对象可以使用循环的方式列出其元素&#xff0c;若多个可迭代对象的长度不一致,则所返回的列表与长度最短的可迭…

WPF中使用DataGrid封装组合控件TreeView+DataGrid

&#xff08;关注博主后&#xff0c;在“粉丝专栏”&#xff0c;可免费阅读此文&#xff09; wpf的功能非常强大&#xff0c;很多控件都是原生的&#xff0c;但是要使用TreeViewDataGrid的组合&#xff0c;就需要我们自己去封装实现。 我们需要的效果如图所示&#x…

汽车品牌官网建设的效果如何

汽车、电动摩托车、自行车等是人们常用的出行工具&#xff0c;头部品牌不少&#xff0c;中小品牌也同样很多&#xff0c;在当今激烈竞争的市场&#xff0c;各商家都希望不断拓客寻求销量增长。由于市场产品同质化严重且无突出特色&#xff0c;加之选择性广&#xff0c;因此在实…

华为鸿蒙应用--封装数据持久化工具:首选项Preferences(鸿蒙工具)-ArkTs

一、使用方法&#xff1a; 0、初始化实例&#xff1a;一般在EntryAbility.ts的onWindowStageCreate中初始化&#xff1b;&#xff08;可忽略&#xff09; 1、将数据写入Preferences实例 function() {let arrayNum: number[] [1, 2, 3];let arrayStr: string[] ["5&quo…

vue3项目 - 使用 pnpm 包管理器来创建项目

创建项目 npm install -g pnpm pnpm create vue 输入项目名称、包名称、选择要安装的依赖&#xff0c;最后 pnpm install pnpm format #规范格式 pnpm dev #启动项目

深度学习 | 常见问题及对策(过拟合、欠拟合、正则化)

1、训练常见问题 1.1、模型架构设计 关于隐藏层的一个万能近似定理&#xff1a; Universal Approximation Theorem&#xff1a;一个具有足够多的隐藏节点的多层前馈神经网络&#xff0c;可以逼近任意连续的函数。&#xff08;Cybenko, 1989&#xff09;—— 必须包含至少一种有…

mysql自增序列 关于mysql线程安全 独享内存 溢出 分析

1 MySQL锁概述 锁是计算机协调多个进程或线程并发访问某一资源的机制。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题&#xff0c;锁冲突也是影响数据库并发访问性能的一个重要因素。 相对其他数据库而言&#xff0c;MySQL的锁机制比较简单&#xff0c…

C++中的内存锁定

内存锁定(memory locking)是确保进程保留在主内存中并且免于分页的一种方法。在实时环境中&#xff0c;系统必须能够保证将进程锁定在内存中&#xff0c;以减少数据访问、指令获取、进程之间的缓冲区传递等的延迟。锁定内存中进程的地址空间有助于确保应用程序的响应时间满足实…

二维码初体验 com.google.zxing 实现

文章目录 一、概述二、实现效果1. 完整版本2. 简化版本 三、源码结构四、完整代码 一、概述 Java 操作二维码的开源项目很多&#xff0c;如 SwetakeQRCode、BarCode4j、Zxing 等&#xff0c;这边以Zxing 为例进行介绍。 二、实现效果 1. 完整版本 选择需要生成QR原始文件&a…

大模型工具_awesome-chatgpt-prompts-zh

https://github.com/PlexPt/awesome-chatgpt-prompts-zh 1 功能 整体功能&#xff0c;想解决什么问题 ChatGPT 中文调教指南&#xff1a;提供一些常用的使用场景及对应的 Prompt 提示 当前解决了什么问题&#xff0c;哪些问题解决不了 针对想解决实际问题&#xff0c;但不知道…

图像识别中的 Vision Transformers (ViT)

引言 Vision Transformers (ViT) 最近已成为卷积神经网络(CNN) 的竞争替代品&#xff0c;而卷积神经网络 (CNN) 目前在不同的图像识别计算机视觉任务中处于最先进的水平。ViT 模型在计算效率和准确性方面比当前最先进的 (CNN) 模型高出近 4 倍。 Transformer 模型已成为自然语…

Diffusion扩散模型学习:图片高斯加噪

高斯分布即正态分布&#xff1b;图片高斯加噪即把图片矩阵每个值和一个高斯分布的矩阵上的对应值相加 1、高斯分布 np.random.normal 一维&#xff1a; import numpy as np import matplotlib.pyplot as pltdef generate_gaussian_noise(mean, std_dev, size):noise np.ran…