MyBatis 底层原理。京东面试:MyBatis 如何实现 “面向接口” 查询的 ?

本文 的 原文 地址

原始的内容,请参考 本文 的 原文 地址

本文 的 原文 地址

尼恩说在前面:

最近大厂机会多了, 在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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值