简单直接的回答是:它们之间是“接口定义”与“SQL映射实现”的关系。 ManageMapper
是一个 Java 接口,它定义了数据库操作的方法签名;而 ManageMapper.xml
是一个 XML 文件,它提供了这些方法签名所对应的具体 SQL 语句实现。MyBatis 框架在运行时通过动态代理技术将它们绑定在一起。
下面我们来详细拆解这个问题,并重点解释“泛型”部分的误解。
1. 角色和关系
组件 | 类型 | 作用 |
---|---|---|
ManageMapper |
Java 接口 | 1. 定义契约:声明一系列操作数据库的方法(如 selectById , insert , update )。2. 提供类型安全:方法的参数和返回值类型是明确的(例如 User selectById(Integer id) )。 |
ManageMapper.xml |
XML 配置文件 | 1. 提供实现:为 ManageMapper 接口中定义的每一个方法,配置具体的 SQL 语句、参数映射、结果集映射等。2. 分离SQL与代码:将易变的 SQL 语句从 Java 代码中解耦出来,便于维护和优化。 |
关系:ManageMapper.xml
文件是 ManageMapper
接口的具体实现者。你可以把它们看作是一份合同的双方:
-
ManageMapper
接口是合同本身,列出了需要完成的任务清单。 -
ManageMapper.xml
是完成这些任务的具体施工方案。
2. 它们是如何被连接起来的?
这种连接不是通过 Java 语法实现的,而是由 MyBatis 框架在运行时完成的。这个过程主要包括以下几步:
-
配置扫描路径:在 MyBatis 的全局配置文件(通常是
mybatis-config.xml
)或 Spring Boot 的配置中,你会设置 Mapper 接口和 XML 文件的扫描路径。<mappers><!-- 告诉 MyBatis 去哪里找 Mapper.xml 文件 --><mapper resource="com/example/mapper/ManageMapper.xml"/><!-- 或者使用包扫描 --><package name="com.example.mapper"/> </mappers>
-
命名空间绑定:在
ManageMapper.xml
文件中,顶层的<mapper>
标签的namespace
属性必须设置为ManageMapper
接口的全限定名(包括包名的完整类路径)。这是连接两者最关键的一步。<!-- ManageMapper.xml --> <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.mapper.ManageMapper"><!-- SQL 配置在这里 --> </mapper>
-
ID 匹配:在 XML 中,每一个 SQL 语句标签(如
<select>
,<insert>
)的id
属性必须与ManageMapper
接口中定义的方法名完全一致。// ManageMapper.java 接口 public interface ManageMapper {User selectById(Integer id); }
<!-- ManageMapper.xml 文件 --> <select id="selectById" parameterType="int" resultType="com.example.entity.User">SELECT * FROM user WHERE id = #{id} </select>
-
动态代理:当你的应用程序运行时,MyBatis 会读取所有配置。当你需要使用
ManageMapper
时(例如通过@Autowired
注入),MyBatis 并不会去创建一个这个接口的实例,而是会动态生成一个代理对象。-
这个代理对象拦截你对接口方法的调用(比如调用
selectById(1)
)。 -
然后根据接口全名(namespace)+ 方法名(id) 作为键,去找到对应的 SQL 语句(
SELECT * FROM user WHERE id = ?
)。 -
接着执行 SQL,并将结果集封装成接口方法所声明的返回值类型(
User
对象)返回。
-
3. 关键澄清:关于“泛型”的误解
你提到 “Managemapper是一个泛型”,这其实是一个常见的误解。
-
ManageMapper
本身通常不是一个泛型接口(Generic Interface)。它就是一个普通的 Java 接口。 -
你之所以会联想到“泛型”,很可能是因为你看到 MyBatis 的通用 Mapper(例如著名的 tk.mybatis.mapper.common.Mapper 或 com.baomidou.mybatisplus.core.mapper.BaseMapper)。
什么是通用 Mapper?
-
它是一个预先定义好的、使用了泛型的接口。例如:
public interface BaseMapper<T> extends Mapper<T> {int insert(T entity);int deleteById(Serializable id);T selectById(Serializable id);// ... 很多其他通用方法 }
-
你的
ManageMapper
通常会继承这个通用 Mapper,并指定具体的实体类型(比如User
)。public interface ManageMapper extends BaseMapper<User> {// 这里可以添加非通用的、自定义的查询方法User selectByUsername(String username); }
-
在这种情况下,
ManageMapper
接口本身因为继承了BaseMapper<User>
,所以它“带有”了泛型的特性(方法参数和返回值类型被确定为User
)。但严格来说,ManageMapper
是一个继承了泛型接口的普通接口。
即使使用了通用 Mapper,其工作原理不变:BaseMapper
中所有泛型方法(如 selectById
) 的 SQL 实现,已经由 MyBatis Plus 或通用 Mapper 的作者们写在了他们提供的 jar 包中的某个 XML 文件里了。而你的 ManageMapper.xml
只需要为你自定义的方法(如 selectByUsername
)提供 SQL 实现即可。如果方法在父接口中已存在且你不需要特殊实现,你甚至可以不写 ManageMapper.xml
文件。
总结
概念 | 解释 |
---|---|
关系 | ManageMapper.java (接口) 定义做什么,ManageMapper.xml (配置文件) 定义怎么做。 |
连接方式 | 通过 MyBatis 框架,利用 namespace (接口全限定名) 和 id (方法名) 进行绑定,并通过动态代理技术实现。 |
“泛型”误解 | ManageMapper 通常不是一个泛型接口,而是一个可能继承了别人写好的泛型接口的普通接口。这种继承关系是为了获得大量开箱即用的通用数据库操作方法。 |
所以,ManageMapper.xml
能够“实现” ManageMapper
接口,完全是 MyBatis 这个“魔法师”在幕后施展的动态代理魔法,而不是 Java 语言层面的实现。