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

手写MyBatis第37弹: 深入MyBatis MapperProxy:揭秘SQL命令类型与动态方法调用的完美适配

🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞

💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝欢迎留言讨论

🔥🔥🔥(源码 + 调试运行 + 问题答疑)

🔥🔥🔥  有兴趣可以联系我。

我们常常在当下感到时间慢,觉得未来遥远,但一旦回头看,时间已经悄然流逝。对于未来,尽管如此,也应该保持一种从容的态度,相信未来仍有许多可能性等待着我们。 

目录

一、MyBatis架构回顾与MapperProxy定位

二、SqlSession的多样化设计:为什么需要多种查询方法?

1. 返回结果类型的多样性

2. 性能优化的考虑

3. API设计的清晰性

三、MapperProxy的动态适配机制

1. SQL命令类型识别

2. 返回类型分析与选择策略

3. 参数处理与传递

四、高级特性与优化策略

1. 批量操作的特殊处理

2. 结果处理器集成

3. 缓存策略与延迟加载

五、实战:自定义MapperProxy扩展

1. 性能监控增强

2. 自动重试机制

六、总结与最佳实践


在现代Java开发中,MyBatis作为一款优秀的持久层框架,以其灵活的SQL映射和简洁的API设计深受开发者喜爱。本文将深入剖析MyBatis核心组件之一的MapperProxy,探讨它是如何根据SQL命令类型动态适配SqlSession的CRUD方法,实现Mapper接口方法与数据库操作的无缝对接。

一、MyBatis架构回顾与MapperProxy定位

在深入了解MapperProxy之前,让我们先简要回顾MyBatis的核心架构。MyBatis通过SqlSession提供数据库操作API,而Mapper接口则定义了这些操作的方法签名。MapperProxy作为连接这两者的桥梁,实现了Java动态代理模式,负责将接口方法调用转化为具体的数据库操作。

 public class MapperProxy<T> implements InvocationHandler {private final SqlSession sqlSession;private final Class<T> mapperInterface;@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 方法调用处理逻辑}}

二、SqlSession的多样化设计:为什么需要多种查询方法?

SqlSession提供了selectOneselectListselectMap等多种查询方法,这种设计并非偶然,而是为了满足不同场景下的数据检索需求:

1. 返回结果类型的多样性

  • selectOne:返回单个对象,适用于查询唯一结果场景

  • selectList:返回对象列表,适用于多结果查询

  • selectMap:返回键值对映射,便于基于特定字段快速查找

2. 性能优化的考虑

不同的方法内部实现针对特定场景进行了优化,比如selectOne在检测到多个结果时会抛出异常,避免意外的数据覆盖。

3. API设计的清晰性

明确的方法命名使得代码更易读和维护,开发者能够直观地理解每个方法的用途。

三、MapperProxy的动态适配机制

MapperProxy的核心职责是根据Mapper接口方法的特征,动态选择适当的SqlSession方法。这一过程涉及多个关键判断:

1. SQL命令类型识别

通过MappedStatement获取sqlCommandType,这是决定调用哪个SqlSession方法的首要因素:

 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodName = method.getName();Class<?> declaringClass = method.getDeclaringClass();String statementId = declaringClass.getName() + "." + methodName;MappedStatement ms = configuration.getMappedStatement(statementId);SqlCommandType sqlCommandType = ms.getSqlCommandType();switch (sqlCommandType) {case SELECT:// 处理查询操作break;case INSERT:return sqlSession.insert(statementId, args);case UPDATE:return sqlSession.update(statementId, args);case DELETE:return sqlSession.delete(statementId, args);default:throw new RuntimeException("Unknown execution method for: " + statementId);}}

2. 返回类型分析与选择策略

对于SELECT操作,需要进一步分析方法的返回类型:

 private Object handleSelect(Method method, String statementId, Object[] args) {Class<?> returnType = method.getReturnType();if (List.class.isAssignableFrom(returnType)) {return sqlSession.selectList(statementId, args);} else if (Map.class.isAssignableFrom(returnType)) {// 处理Map返回类型,可能需要额外的key配置return sqlSession.selectMap(statementId, args, method.getAnnotation(MapKey.class).value());} else if (returnType.isArray()) {// 数组类型处理List<?> result = sqlSession.selectList(statementId, args);return convertToArray(result, returnType.getComponentType());} else {// 默认为selectOne,但需要验证结果数量List<?> result = sqlSession.selectList(statementId, args);if (result.size() == 1) {return result.get(0);} else if (result.size() > 1) {throw new TooManyResultsException("Expected one result (or null) but found: " + result.size());} else {return null;}}}

3. 参数处理与传递

MapperProxy还需要正确处理方法的参数,支持多种参数传递方式:

private Object wrapParameters(Object[] args) {if (args == null || args.length == 0) {return null;} else if (args.length == 1) {return args[0];} else {// 多参数处理,可封装为Map或使用@Param注解Map<String, Object> paramMap = new HashMap<>();for (int i = 0; i < args.length; i++) {paramMap.put("param" + (i + 1), args[i]);}return paramMap;}}

四、高级特性与优化策略

1. 批量操作的特殊处理

对于批量操作,MyBatis提供了特殊的API和优化策略:

 case BATCH:// 批量操作处理if (!sqlSession.isBatching()) {sqlSession.startBatch();}return method.invoke(this, args);

2. 结果处理器集成

支持自定义结果处理器,增强结果集处理的灵活性:

 if (method.isAnnotationPresent(ResultHandler.class)) {ResultHandler<?> handler = (ResultHandler<?>) args[args.length - 1];return sqlSession.select(statementId, wrapParameters(args), handler);}

3. 缓存策略与延迟加载

MapperProxy还需要与MyBatis的缓存机制和延迟加载功能协同工作:

 if (ms.getCache() != null && ms.isUseCache()) {// 缓存命中逻辑Object cached = cache.getObject(statementId);if (cached != null) {return cached;}}

五、实战:自定义MapperProxy扩展

通过扩展MapperProxy,我们可以实现一些高级功能:

1. 性能监控增强

 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long startTime = System.currentTimeMillis();try {return super.invoke(proxy, method, args);} finally {long cost = System.currentTimeMillis() - startTime;log.debug("Method {} executed in {} ms", method.getName(), cost);}}

2. 自动重试机制

for (int retry = 0; retry < maxRetries; retry++) {try {return super.invoke(proxy, method, args);} catch (SQLException e) {if (isRetryableException(e) && retry < maxRetries - 1) {continue;}throw e;}
}

六、总结与最佳实践

MapperProxy作为MyBatis的核心组件,通过动态代理技术实现了Mapper接口方法与SqlSessionCRUD操作的无缝对接。其设计巧妙之处在于:

  1. 职责分离:将SQL命令类型判断与具体执行分离,符合单一职责原则

  2. 灵活适配:根据返回类型自动选择最合适的查询方法

  3. 扩展性强:通过配置和扩展支持各种复杂场景

在实际开发中,理解MapperProxy的工作原理有助于:

  • 更好地调试Mapper接口相关问题

  • 根据业务需求选择合适的返回类型

  • 优化数据库操作性能

  • 实现自定义的数据访问逻辑

通过深入理解MapperProxy的设计思想和实现机制,我们不仅能够更好地使用MyBatis,还能够在遇到复杂业务场景时做出更合理的技术决策。


进一步学习建议

  1. 阅读MyBatis官方文档中关于Mapper接口和SqlSession的部分

  2. 深入研究Java动态代理机制

  3. 探索MyBatis-Spring中MapperScannerConfigurer的工作原理

  4. 了解MyBatis的插件开发,实现自定义的拦截器功能

希望本文能够帮助您深入理解MyBatis的核心机制,并在实际项目中更加得心应手地使用这一优秀的持久层框架。


💖学习知识需费心,
📕整理归纳更费神。
🎉源码免费人人喜,
🔥码农福利等你领!

💖常来我家多看看,
📕我是程序员扣棣,
🎉感谢支持常陪伴,
🔥点赞关注别忘记!

💖山高路远坑又深,
📕大军纵横任驰奔,
🎉谁敢横刀立马行?
🔥唯有点赞+关注成!

http://www.dtcms.com/a/352884.html

相关文章:

  • 特征降维-特征组合
  • YOLO 目标检测:数据集构建(LabelImg 实操)、评估指标(mAP/IOU)、 NMS 后处理
  • Java全栈开发工程师的面试实战:从基础到微服务
  • 科普 | 5G支持的WWC架构是个啥(2)?
  • Android系统框架知识系列(十七):Telephony Service - 移动通信核心引擎深度解析
  • 5G NR学习笔记 预编码(precoding)和波束赋形(beamforming)
  • DAY 58 经典时序预测模型2
  • 不用伪基站也能攻破5G?Sni5Gect框架如何实现“隐形攻击”
  • spire.doc在word中生成公式
  • OpenCV实战1.信用卡数字识别
  • 第1.7节:机器学习 vs 深度学习 vs 强化学习
  • 20.19 LoRA微调Whisper终极指南:3步实现中文语音识别错误率直降37.8%
  • Apifox 8 月更新|新增测试用例、支持自定义请求示例代码、提升导入/导出 OpenAPI/Swagger 数据的兼容性
  • TDengine与StarRocks在技术架构和适用场景上有哪些主要区别?
  • 【C++】set 容器的使用
  • 面试记录6 c++开发工程师
  • 【PostgreSQL内核学习:通过 ExprState 提升哈希聚合与子计划执行效率】
  • 前端漏洞(下)- URL跳转漏洞
  • buuctf——web刷题第四页
  • Ansible模块实战,操作技巧
  • 局部厚铜:PCB技术革新,构筑电气新时代的动力基石
  • AGDO-BP+NSGAII梯度下降优化算法优化BP神经网络+NSGAII多目标优化算法,三目标和四目标案例
  • Spring Start Here 读书笔记:附录A. Architectural approaches
  • Linux系统深度优化指南:CPU、I/O与内核参数调优实战
  • C++:对拍(教程超详细)
  • 【微服务】SpringBoot 整合 Easy-Es 实战操作详解
  • XC6SLX75-2FGG484C Xilinx Spartan-6 LX FPGA
  • 一文详解 LangChain4j AiServices:自动代理实现大模型交互
  • 从文本到二进制:HTTP/2不止于性能,更是对HTTP/1核心语义的传承与革新
  • C++:知识点小结