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

MyBatis 如何将 Mapper 接口与其 XML 映射文件关联:深入原理与实现

MyBatis 如何将 Mapper 接口与其 XML 映射文件关联:深入原理与实现

1. 概述

MyBatis 是一个简单、灵活的持久层框架,它通过 SQL 语句将 Java 对象与数据库进行映射。MyBatis 支持基于 XML 和注解的配置方式。在实际开发中,XML 映射文件与 Mapper 接口的关联是 MyBatis 的核心功能之一。通过这种关联,开发者可以在 Mapper 接口中定义方法,并在 XML 文件中编写 SQL 语句,从而实现数据操作。

2. Mapper 接口与 XML 映射文件的基本结构

首先,我们需要了解 Mapper 接口和 XML 映射文件的基础结构:

Mapper 接口(Java):
public interface UserMapper {User selectUserById(int id);
}
XML 映射文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper"><select id="selectUserById" parameterType="int" resultType="com.example.model.User">SELECT * FROM users WHERE id = #{id}</select>
</mapper>

Mapper 接口和 XML 映射文件通过以下方式关联:

  • namespace:XML 映射文件中的 namespace 属性值必须与 Mapper 接口的全限定名一致,即 com.example.mapper.UserMapper
  • id:XML 文件中 SQL 语句的 id 值要与接口中的方法名保持一致,如 selectUserById

这样,MyBatis 就能根据接口中的方法名找到对应的 SQL 语句并执行。

3. MyBatis 如何建立关联的实现机制

MyBatis 内部是如何将 Mapper 接口与 XML 文件关联起来的?接下来深入讲解具体的流程。

3.1 Mapper 接口代理机制

MyBatis 使用动态代理模式为每个 Mapper 接口创建代理对象。当你调用 UserMapper 中的方法时,实际上调用的是 MyBatis 生成的代理对象。这个代理对象会根据方法名查找与之关联的 SQL 语句,并将参数传入到 SQL 中执行,最后返回结果。

代码示例:

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.selectUserById(1);

sqlSession.getMapper(UserMapper.class) 会通过 MyBatis 的代理工厂为 UserMapper 创建一个代理对象。当调用 selectUserById(1) 时,代理对象会根据接口的方法名查找相应的 SQL 语句。

3.2 MapperRegistryMapperProxyFactory

在 MyBatis 内部,MapperRegistry 是负责管理和维护 Mapper 接口与其代理工厂的核心类。它会将所有的 Mapper 接口注册进来并生成相应的代理对象。

MapperProxyFactory 是为每个 Mapper 接口创建代理对象的工厂类。它利用 java.lang.reflect.Proxy 来动态生成代理对象,并通过 MapperProxy 处理具体的 SQL 调用。

关联过程:

  1. MyBatis 通过 MapperRegistry 注册 Mapper 接口。
  2. 当调用 getMapper 方法时,MapperProxyFactory 生成相应的代理对象。
  3. 代理对象通过 MapperProxy 调用对应的 SQL 语句。
3.3 XML 文件解析与绑定

在 MyBatis 启动时,所有的 Mapper 映射文件会被解析并加载到 Configuration 对象中。Configuration 是 MyBatis 的核心配置类,它包含了所有与 Mapper 相关的配置信息,包括 SQL 映射、缓存、拦截器等。

MyBatis 解析 XML 映射文件时,主要通过以下几步:

  • 读取 namespace,与对应的 Mapper 接口进行匹配。
  • 读取 id 属性,将其与接口中的方法进行对应。
  • 将 SQL 语句和方法签名绑定起来,以便后续调用。

MyBatis 使用 XMLMapperBuilder 类解析 XML 文件。它通过解析 XML 节点,生成对应的 MappedStatement 对象,每个 MappedStatement 对象代表一个 SQL 语句与方法的映射关系。

解析过程:

  1. MyBatis 启动时,会扫描配置文件中指定的 mapper 文件。
  2. 使用 XMLMapperBuilder 类解析 XML 文件,读取 namespaceid
  3. 将解析到的 SQL 语句和 Mapper 接口方法绑定起来,生成 MappedStatement 对象。
  4. MappedStatement 被存储在 Configuration 对象的 mappedStatements 集合中。
4. 关联过程详细示例

假设我们有以下配置:

Mapper 接口:

public interface OrderMapper {Order selectOrderById(int id);
}

XML 映射文件:

<mapper namespace="com.example.mapper.OrderMapper"><select id="selectOrderById" parameterType="int" resultType="com.example.model.Order">SELECT * FROM orders WHERE id = #{id}</select>
</mapper>

核心关联流程:

  1. 加载 XML 文件:MyBatis 启动时,通过 SqlSessionFactoryBuilder 加载配置文件 mybatis-config.xml,并根据配置文件路径加载 OrderMapper.xml
  2. 解析 Mapper 文件XMLMapperBuilder 解析 XML 文件,读取 namespaceid
  3. 生成 MappedStatement:将 selectOrderById 方法与对应的 SQL 语句绑定,生成 MappedStatement 对象并存储在 Configuration 中。
  4. 代理对象的生成sqlSession.getMapper(OrderMapper.class) 调用时,MyBatis 通过 MapperProxyFactoryOrderMapper 创建代理对象。
  5. 执行 SQL 语句:当调用 selectOrderById 方法时,代理对象会根据方法名查找 MappedStatement,并执行对应的 SQL 语句,最终将结果返回。
5. 动态 SQL 与高级应用

MyBatis 不仅支持静态 SQL,还支持动态 SQL,可以根据条件动态生成 SQL 语句。在 XML 文件中,可以使用 <if><choose><foreach> 等标签来构建灵活的 SQL 语句。

动态 SQL 示例:

<select id="selectOrders" resultType="com.example.model.Order">SELECT * FROM ordersWHERE 1=1<if test="status != null">AND status = #{status}</if><if test="customerId != null">AND customer_id = #{customerId}</if>
</select>

这种方式让 MyBatis 能够根据传入的参数动态拼接 SQL,提升了灵活性。

6. 总结

MyBatis 中 Mapper 接口与 XML 文件的关联过程,主要通过 namespaceid 来匹配。在内部,MyBatis 通过代理模式为 Mapper 接口生成代理对象,通过 MappedStatement 实现 SQL 语句与方法的绑定。这个过程使得开发者只需专注于业务逻辑,而不必过多关注底层的 SQL 细节。


整理不易,如果对你有帮助,那就点个免费的赞吧😀

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 电脑浏览器访问华为路由器报错,无法访问路由器web界面:ERR_SSL_VERSION_OR_CIPHER_MISMATCH 最简单的解决办法!
  • AJAX(一)HTTP协议(请求响应报文),AJAX发送请求,请求问题处理
  • LabVIEW提高开发效率技巧----VI服务器和动态调用
  • 怎么检查cuda是否安装成功(以及查看cuda的安装位置)
  • 氢能源多旋翼无人机技术详解
  • Linux入门1
  • 【MySQL-初级】mysql基础操作(账户、数据库、表的增删查改)
  • [C#学习笔记]Newtonsoft.Json
  • 深度学习常见面试题及答案(1~5)
  • 随着越来越多的AI机器人渗透社交平台,各个平台都在制定新规则以应对
  • 上汽大众:存储成本节约85%,查询性能提升5倍|OceanBase案例
  • Istio:微服务网格的强大工具,Istio介绍
  • 初学者如何快速入门大语言模型(LLM)?
  • JVM虚拟机栈
  • 弹性负载均衡ELB 详解和设置方法
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • 30秒的PHP代码片段(1)数组 - Array
  • CAP理论的例子讲解
  • Docker入门(二) - Dockerfile
  • Python学习之路13-记分
  • SpriteKit 技巧之添加背景图片
  • vue-loader 源码解析系列之 selector
  • 基于组件的设计工作流与界面抽象
  • 聚类分析——Kmeans
  • 前嗅ForeSpider中数据浏览界面介绍
  • 如何使用 JavaScript 解析 URL
  • 使用Maven插件构建SpringBoot项目,生成Docker镜像push到DockerHub上
  • 应用生命周期终极 DevOps 工具包
  • kubernetes资源对象--ingress
  • 曾刷新两项世界纪录,腾讯优图人脸检测算法 DSFD 正式开源 ...
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • ​你们这样子,耽误我的工作进度怎么办?
  • #如何使用 Qt 5.6 在 Android 上启用 NFC
  • (24)(24.1) FPV和仿真的机载OSD(三)
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (苍穹外卖)day03菜品管理
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (几何:六边形面积)编写程序,提示用户输入六边形的边长,然后显示它的面积。
  • (考研湖科大教书匠计算机网络)第一章概述-第五节1:计算机网络体系结构之分层思想和举例
  • (七)Flink Watermark
  • (十三)Flask之特殊装饰器详解
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (一一四)第九章编程练习
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • ***php进行支付宝开发中return_url和notify_url的区别分析
  • *上位机的定义
  • .bat批处理(一):@echo off
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • .NET Core 版本不支持的问题
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .NET Core 中的路径问题