本文 的 原文 地址
原始的内容,请参考 本文 的 原文 地址
尼恩说在前面:
最近大厂机会多了, 在45岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、shein 希音、shopee、百度、网易的面试资格,遇到很多很重要的面试题:
MyBatis 如何实现 “面向接口” 查询的 ?
昨天面试京东问 : mybatis 的用接口怎么实现查询的,Java 线程有几种状态[破涕为笑]
前几天 小伙伴面试 京东,遇到了这个问题。但是由于 没有回答好,导致面试挂了。
小伙伴面试完了之后,来求助尼恩。
那么,遇到 这个问题,该如何才能回答得很漂亮,才能 让面试官刮目相看、口水直流。
所以,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。
当然,这道面试题,以及参考答案,也会收入咱们的 《尼恩Java面试宝典》V175版本PDF集群,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。
最新《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请关注本公众号【技术自由圈】获取,后台回复:领电子书
京东面试:MyBatis 如何实现 “面向接口” 查询的 ?

MyBatis 的接口怎么实现 面向查询的?
这是一个关于 MyBatis 的接口绑定(Interface Binding)机制的问题,也是 MyBatis 相比传统 DAO 模式最方便的特性之一。
核心答案
MyBatis 通过JDK 动态代理技术,在运行时, 动态为 Mapper 接口 生成代理实现类(MapperProxy)。
MyBatis JDK 动态代理 的目标: 实现 “仅定义接口、无需手动编写实现类” , 完成数据库操作。
“面向接口” 的核心机制 与 实现步骤
1. 核心机制:JDK 动态代理
MyBatis 是“面向接口” 查询, 接口的实现类是 JDK 动态代理创建 的。 或者说, MyBatis 依赖 JDK 原生动态代理技术实现接口与数据库操作的绑定,而非手动编写接口实现类。
当定义好 Mapper 接口后,MyBatis 会 为该接口创建一个 MapperProxy 代理对象,并将其注册到 Spring 容器(若整合 Spring)中。
MapperProxy 代理对象 在应用初始化阶段(如 Spring 容器启动时)创建。 后续注入接口时,实际获取的是这个代理对象,接口方法的调用会被转发到代理对象的逻辑中。
2. “面向接口” 实现步骤
我们先来看一张核心流程图,帮助你建立整体认知:

这张图就是整个 MyBatis 接口查询的核心流程。下面我们一层一层地展开讲。
第一步:定义 Mapper 接口
创建 Java 接口,接口中的方法签名(方法名、参数类型、返回类型)需与后续 SQL 操作的配置对应,方法名将作为匹配 SQL 的核心标识。
public interface UserMapper {
// 单条查询:根据ID查用户
User selectUserById(Long id);
// 批量查询:查询所有用户
List<User> selectAllUsers();
// 插入操作:新增用户
int insertUser(User user);
}
第二步:配置 SQL(XML 式或注解式)
MyBatis 支持两种 SQL 配置方式,需确保 SQL 与接口方法绑定:
第一种SQL 配置方式: XML 式:
创建与接口同名的 XML 文件(如 UserMapper.xml),通过 namespace 指定接口全限定名,id 与接口方法名完全一致。
<?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">
<!-- namespace必须是Mapper接口的全限定名 -->
<mapper namespace="com.jd.dao.UserMapper">
<!-- id与接口方法名一致,resultType指定返回实体类型 -->
<select id="selectUserById" resultType="com.jd.model.User">
SELECT * FROM user WHERE id = #{id}
</select>
<select id="selectAllUsers" resultType="com.jd.model.User">
SELECT * FROM user
</select>
</mapper>
第一种SQL 配置方式: 注解式
直接在接口方法上通过 @Select/@Insert 等注解编写 SQL,无需 XML 文件,SQL 与方法直接绑定。
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User selectUserById(Long id);
}
第三步:注入接口并使用
在 Service 层通过 @Autowired(或 @Resource)注入 Mapper 接口(实际注入的是 MyBatis 生成的 MapperProxy 代理对象),直接调用接口方法即可触发 SQL 执行。
@Service
public class UserService {
// 注入的是MyBatis生成的代理对象,而非接口本身
@Autowired
private UserMapper userMapper;
public User getUserById(Long id) {
// 调用接口方法 → 实际触发代理对象的invoke()逻辑
return userMapper.selectUserById(id);
}
}
3. 执行过程(工作原理拆解)
当调用 userMapper.selectUserById(1L) 时,底层执行流程如下:
(1) 代理对象拦截调用:
方法调用被 MapperProxy 代理对象的 invoke() 方法拦截;
(2) 生成 SQL 唯一标识:
invoke() 方法根据 “接口全限定名 + 方法名” 生成唯一标识(如 com.jd.dao.UserMapper.selectUserById);
(3) 匹配 MappedStatement
通过唯一标识从 MyBatis 全局配置(Configuration)中找到对应的 MappedStatement

最低0.47元/天 解锁文章
1156

被折叠的 条评论
为什么被折叠?



