当前位置: 首页 > backend >正文

揭秘MyBatis核心类MappedStatement

MappedStatement-封装一次sql映射语句的所有配置信息

  • MappedStatement: 是 MyBatis 框架中核心类

核心功能:封装一次 SQL 映射语句(SQL Statement)的所有配置信息

​ 使用了内部静态类 Builder 来实现构建者模式, 保证 MappedStatement 的不可变性和构造过程的灵活性

作用
MappedStatement : 代表 MyBatis 中一个具体的映射语句配置,包含了执行 SQL 所需的所有信息

MappedStatement.Builder 是用于构建 MappedStatement 实例的构造器,避免构造参数过多,代码易读且易扩展。

public static class Builder {private MappedStatement mappedStatement = new MappedStatement();public Builder(Configuration configuration, String id, SqlSource sqlSource, SqlCommandType sqlCommandType) {// 必填参数初始化及默认值赋值}// 各种 setter 风格的方法链,方便链式调用public Builder resource(String resource) { ... }public Builder fetchSize(Integer fetchSize) { ... }// ... 省略public MappedStatement build() {// 校验必须字段非空// 包装不可变的 List 等return mappedStatement;}
}

主要字段说明

字段名类型作用描述
resourceString映射语句来源资源(一般为 XML 路径)
configurationConfigurationMyBatis 全局配置对象
idString映射语句唯一标识(namespace + id)
fetchSizeInteger批量获取结果集大小
timeoutInteger执行超时时间
statementTypeStatementTypeSQL 语句类型(STATEMENT, PREPARED, CALLABLE)
resultSetTypeResultSetType结果集类型(FORWARD_ONLY 等)
sqlSourceSqlSourceSQL 语句提供者,负责动态 SQL 解析
cacheCache缓存策略
parameterMapParameterMap参数映射
resultMapsList<ResultMap>结果映射列表
flushCacheRequiredboolean是否需要刷新缓存
useCacheboolean是否使用二级缓存
resultOrderedboolean结果是否有序
sqlCommandTypeSqlCommandTypeSQL 类型(SELECT, INSERT, UPDATE, DELETE)
keyGeneratorKeyGenerator主键生成器
keyPropertiesString[]主键属性列表
keyColumnsString[]主键列列表
hasNestedResultMapsboolean是否存在嵌套的结果映射
databaseIdString数据库标识,支持多数据库映射
statementLogLog语句执行日志
langLanguageDriver语言驱动,处理不同脚本语言(XML、注解等)
resultSetsString[]多结果集名称

Builder 中常用方法详解

  • parameterMap(ParameterMap parameterMap):指定参数映射。
  • resultMaps(List<ResultMap> resultMaps):指定结果映射,并根据结果映射判断是否有嵌套结果映射。
  • keyGenerator(KeyGenerator keyGenerator):指定主键生成策略,默认根据配置和 SQL 类型确定。
  • keyProperty(String keyProperty) / keyColumn(String keyColumn):指定主键对应的属性名和列名。
  • lang(LanguageDriver driver):指定语言驱动,如 XML 语言驱动。
  • build():构造最终的不可变 MappedStatement 实例。

关键方法

  • 根据参数对象,从 sqlSource 解析出最终 SQL 和参数映射。
  • 如果没有参数映射,则使用默认参数映射重构。
  • 进一步检查参数映射中是否有嵌套结果映射,标记 hasNestedResultMaps
public BoundSql getBoundSql(Object parameterObject) {BoundSql boundSql = sqlSource.getBoundSql(parameterObject);List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();if (parameterMappings == null || parameterMappings.isEmpty()) {boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);}// 检查参数映射中是否包含嵌套结果映射(解决 issue #30)for (ParameterMapping pm : boundSql.getParameterMappings()) {String rmId = pm.getResultMapId();if (rmId != null) {ResultMap rm = configuration.getResultMap(rmId);if (rm != null) {hasNestedResultMaps |= rm.hasNestedResultMaps();}}}return boundSql;
}

此方法不能用的原因

在用 MyBatis-Plus + MybatisInterceptor 链机制,而你注册的是 原始 MyBatis 插件机制

MyBatis-Plus 3.4.0+ 默认只支持 InnerInterceptor

注册的是 MyBatis 原生的插件(实现了 org.apache.ibatis.plugin.Interceptor),
而 MyBatis-Plus 的默认插件执行链不包含原生 Interceptor,必须你通过手动注册。

你可以从日志中看到这些被拦截的类是:

复制编辑
plugin target: class com.baomidou.mybatisplus.core.MybatisParameterHandler

这是 MyBatis-Plus 定制过的执行器链条(它使用了自己的 InterceptorChain)。

故整体变动改为实现 InnerInterceptor

@Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,ResultHandler resultHandler, BoundSql boundSql) {// 判断是否跳过if (MerchantIsolationContext.isSkipped()) {return;}try {String originalSql = boundSql.getSql().toLowerCase(Locale.ROOT);log.info("===> into MerchantIsolationInnerInterceptor, msId = {}, SQL = {}", ms.getId(), originalSql);if (!originalSql.contains("from") || originalSql.contains(MerchantCenterConstant.FIELD_MERCHANT_ID)) {return;}Class<?> doClass = extractDoClass(ms);if (CheckUtil.isEmpty(doClass)) {log.warn("Unable to extract DO class, skipping merchant_id injection");return;}if (!hasMerchantId(doClass)) {return;}if (isMultiTable(originalSql)) {log.warn("Multi-table SQL detected, skipping merchant_id injection: {}", originalSql);return;}Long merchantId = extractMerchantId(parameter);if (CheckUtil.isEmpty(merchantId)) {throw BaseIllegalArgumentException.newException(BaseIllegalArgumentException.BASE_ILLEGAL_ARGUMENT,"No merchant_id provided and no skip claim");}String modifiedSql = appendMerchantCondition(boundSql.getSql(), merchantId);log.info("SQL injection merchant_id completed: {}", modifiedSql);// 替换 SQL(MyBatis-Plus 特殊处理)ReflectUtil.setFieldValue(boundSql, "sql", modifiedSql);} catch (Exception e) {log.error("MerchantIsolationInnerInterceptor Error: {}", e.getMessage(), e);}
}
http://www.xdnf.cn/news/17340.html

相关文章:

  • 【Datawhale AI夏令营】基于多模态RAG的企业财报问答系统
  • Vue3 生命周期
  • Go语言实战案例:表单提交数据解析
  • 多模态RAG赛题实战--Datawhale AI夏令营
  • 39.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--扩展功能--调整发布脚本
  • 通过 Docker 运行 Prometheus 入门
  • C# 通过第三方库INIFileParser管理INI配置文件
  • 2025年渗透测试面试题总结-09(题目+回答)
  • 实战:MyBatis 中 db.properties 的正确配置与最佳实践
  • RAGFoundry:面向检索增强生成的模块化增强框架
  • 五、RuoYi-Cloud-Plus 前端项目部署以及如何改后端请求地址。
  • 【CTF】PHP反序列化基础知识与解题步骤
  • Java 大视界 -- Java 大数据在智能医疗手术机器人操作数据记录与性能评估中的应用(390)
  • 深入剖析Spring MVC核心原理:从请求到响应的魔法解密
  • Java-线程线程的创建方式
  • 【线性代数】线性方程组与矩阵——(3)线性方程组解的结构
  • kubectl get node k8s-node01 -o yaml | grep taint -B 5 -A 5
  • 电子电气架构 --- 48V车载供电架构
  • 第16届蓝桥杯Scratch选拔赛初级及中级(STEMA)2024年11月24日真题
  • 阿里Qwen-Image本地部署详细指南
  • SAP在越南投资1.75亿美元建设研发中心
  • 多线程(四) --- 线程安全问题
  • JS逆向实战案例之----【通姆】252个webpack模块自吐
  • jQuery 零基础学习第一天
  • 进阶向:Python编写网页爬虫抓取数据
  • PG靶机 - Shiftdel
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(15):文法+单词第5回
  • 99-基于Python的京东手机数据分析及预测系统
  • 母线电压采样芯片的四大类——汽车级选型对比表
  • git查看单个文件的所有修改记录