Mybatis中支持缓存的query与不支持缓存的query

mybatis拦截器中,通常添加两个query的签名方法,如下:

@Intercepts({@Signature(type = Executor.class,method = "query",args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),@Signature(type = Executor.class,method = "query",args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})
})第一个,表示不支持缓存的query。第二个,表示支持缓存的query。a.某些数据变化不频繁,但查询非常频繁。缓存可以减少数据库查询次数,提高响应速度。b.在分页查询中,缓存可以显著提高性能,尤其是当用户频繁浏览不同页面时。c.对于复杂查询,生成的 SQL 可能涉及多个表的联接,执行时间较长。缓存可以显著减少这种查询的执行次数。

具体区别

  1. 访问频率和实时性

    • 不需要缓存:每次查询都直接访问数据库,适用于数据变化频繁或需要最新数据的场景。
    • 需要缓存:查询结果可以被缓存,适用于数据变化不频繁但查询频繁的场景。
  2. 性能和资源使用

    • 不需要缓存:每次都访问数据库,可能会增加数据库负载。
    • 需要缓存:利用缓存减少数据库访问次数,显著提高性能和响应速度。

有哪些方法,可以判断是否应用缓存:
1.通过sql语句标识:

@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class CacheInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];String sqlId = mappedStatement.getId();// 假设我们有一个特定的SQL ID需要使用缓存if ("com.example.mapper.UserMapper.selectUsers".equals(sqlId)) {// 使用缓存逻辑CacheKey cacheKey = ...; // 创建 CacheKeyBoundSql boundSql = ...; // 获取 BoundSql// 执行带缓存的查询return executor.query(mappedStatement, parameter, rowBounds, resultHandler, cacheKey, boundSql);} else {// 直接访问数据库return invocation.proceed();}}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// 可选:设置一些属性}
}

2.通过注解或配置

<select id="selectUsers" resultType="User" useCache="true">SELECT * FROM users
</select>@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class CacheInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];Object parameter = invocation.getArgs()[1];RowBounds rowBounds = (RowBounds) invocation.getArgs()[2];ResultHandler resultHandler = (ResultHandler) invocation.getArgs()[3];Executor executor = (Executor) invocation.getTarget();// 读取自定义属性Boolean useCache = (Boolean) mappedStatement.getConfiguration().getVariables().get("useCache");if (useCache != null && useCache) {// 使用缓存逻辑CacheKey cacheKey = executor.createCacheKey(mappedStatement, parameter, rowBounds, mappedStatement.getBoundSql(parameter));BoundSql boundSql = mappedStatement.getBoundSql(parameter);return executor.query(mappedStatement, parameter, rowBounds, resultHandler, cacheKey, boundSql);} else {// 直接访问数据库return invocation.proceed();}}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// 可选:设置一些属性}
}

3.通过业务逻辑判断

@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class CacheInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];Object parameter = invocation.getArgs()[1];RowBounds rowBounds = (RowBounds) invocation.getArgs()[2];ResultHandler resultHandler = (ResultHandler) invocation.getArgs()[3];Executor executor = (Executor) invocation.getTarget();// 根据业务逻辑判断if (shouldUseCache(mappedStatement, parameter)) {// 使用缓存逻辑CacheKey cacheKey = executor.createCacheKey(mappedStatement, parameter, rowBounds, mappedStatement.getBoundSql(parameter));BoundSql boundSql = mappedStatement.getBoundSql(parameter);return executor.query(mappedStatement, parameter, rowBounds, resultHandler, cacheKey, boundSql);} else {// 直接访问数据库return invocation.proceed();}}private boolean shouldUseCache(MappedStatement mappedStatement, Object parameter) {// 根据业务逻辑判断是否使用缓存// 示例:如果参数包含某个特定值,则使用缓存if (parameter instanceof Map) {Map<String, Object> paramMap = (Map<String, Object>) parameter;return "useCache".equals(paramMap.get("cacheFlag"));}return false;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// 可选:设置一些属性}
}

两个query方法的区别:

其实,mapper文件中useCache参数会用来构建MappedStatement对象。即ms.isUseCache()被用来判断是否走缓存逻辑。

或者 通过@Options注解方式配置useCache参数:

import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Select;public interface UserMapper {@Select("SELECT * FROM your_table WHERE your_conditions")@Options(useCache = false)List<YourResultType> selectRealTimeData();
}
public abstract class BaseExecutor implements Executor {@Overridepublic <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 query(ms, parameter, rowBounds, resultHandler, key, boundSql);}@Overridepublic <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {// 检查二级缓存if (ms.isUseCache() && resultHandler == null) {Cache cache = ms.getCache();if (cache != null) {// 从二级缓存中获取结果@SuppressWarnings("unchecked")List<E> list = (List<E>) cache.getObject(key);if (list != null) {return list;}}}// 如果缓存没有命中,执行数据库查询List<E> result = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);// 将结果存入二级缓存if (ms.isUseCache() && resultHandler == null && cache != null) {cache.putObject(key, result);}return result;}protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException;
}

其中,mybatis中,启用二级缓存的配置方式:

1.全局配置

<configuration><!-- 其他配置 --><settings><setting name="cacheEnabled" value="true"/></settings>
</configuration>

2.映射文件配置

<mapper namespace="com.example.mapper.UserMapper"><!-- 启用二级缓存 --><cache/><!-- 其他映射配置 --><select id="selectUsers" resultType="User">SELECT * FROM users</select>
</mapper>

3.自定义缓存配置

<mapper namespace="com.example.mapper.UserMapper"><!-- 启用二级缓存,并设置自定义属性 --><cacheeviction="LRU"       <!-- 缓存回收策略:LRU(默认) -->flushInterval="60000" <!-- 刷新间隔,单位:毫秒 -->size="512"           <!-- 缓存大小 -->readOnly="true"/>    <!-- 只读缓存 --><!-- 其他映射配置 --><select id="selectUsers" resultType="User">SELECT * FROM users</select>
</mapper>

4.使用注解配置

import org.apache.ibatis.annotations.CacheNamespace;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.cache.decorators.LruCache;@CacheNamespace(eviction = LruCache.class,   // 缓存回收策略flushInterval = 60000,       // 刷新间隔,单位:毫秒size = 512,                  // 缓存大小readWrite = false            // 是否可读写
)
public interface UserMapper {@Select("SELECT * FROM users")List<User> selectUsers();
}

 

提取有效信息:

private Object extractRouteParameterValue(Invocation invocation, Set<String> routerPropertyNames) {Object routeValue = null;try {Object[] args = invocation.getArgs();MappedStatement mappedStatement = (MappedStatement) args[0];Object parameterObject = args[1];BoundSql boundSql = mappedStatement.getBoundSql(parameterObject);List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();TypeHandlerRegistry typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();Configuration configuration = mappedStatement.getConfiguration();for (ParameterMapping parameterMapping : parameterMappings) {String rawPropertyName = parameterMapping.getProperty();String actualPropertyName = resolvePropertyName(rawPropertyName);if (!routerPropertyNames.contains(actualPropertyName.toLowerCase())) {continue;}// copy from DefaultParameterHandler.setParameter方法//  ParameterMode.IN 输入, OUT、INOUT 是在存储过程中使用,暂时无视if (parameterMapping.getMode() != ParameterMode.OUT) {String propertyName = parameterMapping.getProperty();if (boundSql.hasAdditionalParameter(propertyName)) {routeValue = boundSql.getAdditionalParameter(propertyName);} else if (parameterObject == null) {routeValue = null;} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {routeValue = parameterObject;} else {MetaObject metaObject = configuration.newMetaObject(parameterObject);routeValue = metaObject.getValue(propertyName);}}if (routeValue != null && hasText(routeValue.toString())) {return routeValue;}throw new DataSourceRoutingException(String.format("未检测到有效的数据库路由,请检测是否传入:(%s)", boundSql.getSql()));}} catch (DataSourceRoutingException dataSourceRoutingException) {throw dataSourceRoutingException;} catch (RuntimeException e) {throw new DataSourceRoutingException(String.format("数据库路由解析异常, invocation method:{%s}, args:{%s}, routerPropertyNames:{%s}",invocation.getMethod().toGenericString(), Arrays.toString(invocation.getArgs()), routerPropertyNames), e);}return null;}

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

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

相关文章

aforg.net简单应用举例

AForge.NET 是一个基于 C# 的开源框架&#xff0c;它提供了一系列用于图像处理、计算机视觉、神经网络、遗传算法、机器人等领域的类库和工具。以下是一个简单的 AForge.NET 应用示例&#xff0c;涉及图像处理中的边缘检测功能。 假设我们想要对一张图片进行边缘检测&#xff…

【Python机器学习】模型评估与改进——留一法交叉验证

留一法也是一种常见的交叉验证方法。 我们可以将留一法交叉验证看作是每折只包含单个样本的k折交叉验证。对于每次划分&#xff0c;选择单个数据点作为测试集。这种方法可能非常耗时&#xff0c;特征是对于大型数据&#xff0c;但是小型数据集上有时可以给出更好的估计结果&am…

HarmonyOS Next开发学习手册——显示图片 (Image)

开发者经常需要在应用中显示一些图片&#xff0c;例如&#xff1a;按钮中的icon、网络图片、本地图片等。在应用中显示图片需要使用Image组件实现&#xff0c;Image支持多种图片格式&#xff0c;包括png、jpg、bmp、svg和gif&#xff0c;具体用法请参考 Image 组件。 Image通过…

Python 算法交易实验75 QTV200后续想法梳理

说明 在第一步获取数据源&#xff0c;然后进入Mongo(第一个数据节点)开始&#xff0c;QTV200的数据流体系就开始动了。后续用多少时间完成不太好确定&#xff0c;短则数周&#xff0c;长则数月。毕竟有过第一版实验的基础&#xff0c;应该还是可以做到的。 下面就是天马行空&…

Spring Cloud Sentinel

官网代码案例: 注意&#xff1a; 1. 引入依赖 <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> 2. 配置文件application.yml spring:cloud:sent…

MIG IP example中的模型文件 -- ddr3_model.sv、 ddr3_model_parameters.vh、WIREDLY.V

关于Xilinx Vivado中MIG (Memory Interface Generator) IP核自带example中的几个关键文件。 WIREDLY.V 文件: 用途: 这是一个用于模拟弱上拉&#xff08;weak pull-up&#xff09;和弱下拉&#xff08;weak pull-down&#xff09;的Verilog模块。在DDR3仿真中&#xff0c;它用于…

解决Python用xpath爬取不到数据的一个思路

前言 最近在学习Python爬虫的知识&#xff0c;既然眼睛会了难免忍不住要实践一把。 不废话直接上主题 代码不复杂&#xff0c;简单的例子奉上&#xff1a; import requests from lxml import etreecookie 浏览器F12网络请求标头里有 user_agent 浏览器F12网络请求标头里有…

Java+Swing+mysql学生考勤管理系统(高分课程项目)

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、Php、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

系统架构设计师 - 计算机网络(1)

计算机网络 计算机网络TCP/IP 协议簇TCP与UDP ★★★DHCP与DNS ★★★DNS 协议应用DHCP 协议应用 网络规划与设计逻辑设计与物理设计 ★★★★逻辑网络设计物理网路设计 层次化网络设计网络冗余设计 网络存储 ★★网络存储方式磁盘阵列 - Raid 大家好呀&#xff01;我是小笙&am…

【面试系列】信息安全分析师高频面试题及详细解答

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来&#xff1a;详细讲解AIGC的概念、核心技术、…

浅谈定时器之泊松随机定时器

浅谈定时器之泊松随机定时器 “泊松随机定时器”(Poisson Random Timer)&#xff0c;它允许你基于泊松分布来随机化请求之间的延迟时间&#xff0c;这对于模拟具有随机到达率的事件特别有用&#xff0c;如用户访问网站或服务的请求。 泊松分布简介 泊松分布是一种统计与概率…

Golang开发:构建支持并发的网络爬虫

Golang开发&#xff1a;构建支持并发的网络爬虫 随着互联网的快速发展&#xff0c;获取网络数据成为了许多应用场景中的关键需求。网络爬虫作为一种自动化获取网络数据的工具&#xff0c;也因此迅速崛起。而为了应对日益庞大的网络数据&#xff0c;开发支持并发的爬虫成为了必…

操作系统真象还原:进一步完善内核

第12章-进一步完善内核 12.1 Linux系统调用浅析 系统调用就是让用户进程申请操作系统的帮助&#xff0c;让操作系统帮其完成某项工作&#xff0c;也就是相当于用户进程调用了操作系统的功能&#xff0c;因此“系统调用”准确地来说应该被称为“操作系统功能调用”。 Linux 系…

【深度笔记】LRU Cache

因为经常使用LRU&#xff08;Least Recently Used&#xff0c;最近最少使用&#xff09;或其他缓存替换策略来管理存储在KV Cache中的数据&#xff0c;保证高效的数据访问。在Transformer等深度学习模型中&#xff0c;KV Cache被广泛应用于存储Self-Attention机制中的中间计算结…

RaysyncCMD-一款及其好用的镭速文件传输工具

在日常的生活及工作流中&#xff0c;文件传输扮演着至关重要的角色&#xff0c;从工作文档、家庭照片到高清视频&#xff0c;每一种数据的迁移都需仰赖高效的文件传输工具。今天&#xff0c;小编今天安利一款性能卓越的文件传输利器——RaysyncCMD。 这是一款专为Windows、Linu…

002-基于Sklearn的机器学习入门:基本概念

本节将继续介绍与机器学习有关的一些基本概念&#xff0c;包括机器学习的分类&#xff0c;性能指标等。同样&#xff0c;如果你对本节内容很熟悉&#xff0c;可直接跳过。 2.1 常见的监督学习方法

智慧渔港:海域感知与岸线监控实施方案(智慧渔港渔船综合管控平台)

文章目录 引言I 技术栈1.1 物理结构图1.2 功能逻辑结构图II 云台(大华)2.1 设备网络SDK运行在Mac平台2.2 WEB无插件开发包III 术语3.1 渔业引言 利用渔船现有的定位导航通讯设备等资源,实现岸线和近岸海域内违法船舶和可疑船舶预警、抓拍、跟踪和行为分析。 在渔船上安装风…

Java中的四种访问权限控制符分别是什么?

在Java编程语言中&#xff0c;访问权限控制符&#xff08;也称为访问修饰符&#xff09;是定义类、变量、方法和构造函数访问范围的关键字。它们确保了Java的封装性原则&#xff0c;允许开发者控制外部对类成员的访问权限。Java提供了四种访问权限控制符&#xff0c;分别是&…

执行yum报错error: cannot open Packages

完整报错内容如下&#xff1a; error: rpmdb: BDB0113 Thread/process 162099/139704678967360 failed: BDB1507 Thread died in Berkeley DB library error: db5 error(-30973) from dbenv->failchk: BDB0087 DB_RUNRECOVERY: Fatal error, run database recovery error: …

可燃气体报警器定期检测:优化与改进策略的探讨

在现代化的工业环境中&#xff0c;可燃气体报警器的作用日益凸显。它们像是我们生产现场的安全卫士&#xff0c;时刻警惕着可能发生的危险&#xff0c;确保我们的工作环境安全、稳定。 然而&#xff0c;要确保这些“卫士”始终忠诚可靠&#xff0c;定期检测就显得尤为重要。 …