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

揭秘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.dtcms.com/a/322977.html

相关文章:

  • Java异常:认识异常、异常的作用、自定义异常
  • ChatGPT 5的编程能力宣传言过其实
  • 97-基于Python的大众点评数据分析预测系统
  • 七、《Serverless架构:按毫秒计费的成本革命》--从新浪AI推理平台50%效能提升看无服务器本质
  • 数据结构——优先级队列(PriorityQueue):一文解决 Top K 问题!
  • 可视化大屏 SDK 数据结构设计:从拖拽组件到最终渲染的全链路
  • 2025-08-09 李沐深度学习13——经典卷积神经网络 (1)
  • 嵌入式知识日常问题记录及用法总结(一)
  • C++2024 年一级
  • Vue3 学习教程,从入门到精通,Vue 3 + Tailwind CSS 全面知识点与案例详解(31)
  • buuctf:inndy_echo、actf_2019_babystack
  • 花生4CL基因家族鉴定及对干旱与盐胁迫响应分析--文献精读157
  • 【AI论文】种子扩散模型:一种具备高速推理能力的大规模扩散语言模型
  • 智慧农业-无人机视角庄稼倒伏农作物倒伏识别分割数据集labelme格式541张1类别
  • C语言指针完全指南:从入门到精通
  • Selenium使用超全指南
  • OpenCV图像裁剪与 ROI 操作
  • 全志刷机工具:PhoenixSuit-全志芯片处理器-刷机工具安装包及最详细使用教程指南
  • Python day39
  • Web3: 用ERC-1400革新公司股权激励
  • 【原创】基于 Flask 的简单文件收集器
  • 【33】C#实战篇——点击按钮弹出指定路径对话框,选择指定类型文件;;;文件过滤器显示指定的一种文件,几种类型文件 同时显示
  • Pytest中实现自动生成测试用例脚本代码
  • 扩散LLM推理新范式:打破生成长度限制,实现动态自适应调节
  • 在ubuntu服务器下安装cuda和cudnn(笔记)
  • ImageJ 实用技巧:通过 Overlay 实现图像透明标记的完整教程
  • NTP /Chrony 网络时间协议
  • 当配置项只支持传入数字,即无法指定单位为rem,需要rem转px
  • 本地连接跳板机
  • 【Windows】成批复制某个特定的文件