欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MyBatis?Mapper?接口是如何找到并執(zhí)行SQL的

 更新時間:2025年09月16日 09:57:39   作者:java干貨  
本文將為你揭開MyBatis這層神秘的面紗,深入剖析其接口與SQL的映射原理,并總結(jié)在Spring?Boot環(huán)境下的最佳實踐和常見陷阱,感興趣的朋友跟隨小編一起看看吧

每一位使用 MyBatis 的 Java 開發(fā)者,都曾體驗過這種“魔法”:我們只定義了一個簡單的 UserMapper 接口,沒有寫任何實現(xiàn)類,但只要在 Service 中注入它并調(diào)用其方法,數(shù)據(jù)庫操作就奇跡般地完成了。

// 在 Service 中
@Autowired
private UserMapper userMapper;
public User getUser(Long id) {
// 只是調(diào)用了一個接口方法
return userMapper.selectById(id);
}

UserMapper 只是一個接口,它沒有實現(xiàn)類,那 userMapper 這個注入的 Bean 到底是什么?selectById 這個方法又是如何與具體的 SQL 語句關(guān)聯(lián)起來的呢?

本文將為你揭開 MyBatis 這層神秘的面紗,深入剖析其接口與 SQL 的映射原理,并總結(jié)在 Spring Boot 環(huán)境下的最佳實踐和常見陷阱。

1. 核心原理:JDK 動態(tài)代理 (Dynamic Proxy)

MyBatis 的“魔法”核心,正是 Java 的 JDK 動態(tài)代理 技術(shù)。

當(dāng)你試圖從 Spring 容器中獲取一個 UserMapper 實例時,Spring 實際上是請求 MyBatis 的 MapperFactoryBean 來創(chuàng)建一個 Bean。MyBatis 并不會去尋找這個接口的實現(xiàn)類,而是利用 JDK 的 Proxy 類,在運行時動態(tài)地為你創(chuàng)建一個該接口的代理對象。

這個代理對象,就是你注入到 Service 中的 userMapper。它具備了 UserMapper 接口的所有方法,但它不是一個普通的實現(xiàn)。你可以把它想象成一個聰明的“中介”或“調(diào)度員”。

當(dāng)你調(diào)用 userMapper.selectById(1L) 時,實際發(fā)生了以下事情:

  • 1. 方法攔截: 這個調(diào)用首先被代理對象攔截。
  • 2. 信息解析: 代理對象會解析出你調(diào)用的信息,包括:
    • • 接口名: com.example.mapper.UserMapper
    • • 方法名: selectById
    • • 參數(shù): 1L
  • 3. SQL 尋址: 這是最關(guān)鍵的一步。代理對象會根據(jù)**“接口名 + 方法名”**這個唯一的坐標(biāo),去 MyBatis 的全局配置中尋找與之對應(yīng)的 SQL 語句。
  • 4. SQL 執(zhí)行: 找到 SQL 后,代理對象會利用底層的 SqlSession,將參數(shù) 1L 傳遞進去,通過 JDBC 執(zhí)行這條 SQL。
  • 5. 結(jié)果映射: 將數(shù)據(jù)庫返回的結(jié)果,根據(jù)配置映射成 Java 對象并返回。

所以,整個問題的關(guān)鍵就變成了:MyBatis 是如何完成第3步——**“SQL 尋址”**的?

2. “尋址”的藝術(shù):兩種主要的映射方式

MyBatis 提供了兩種方式,來告訴代理對象“接口方法”和“SQL語句”之間的對應(yīng)關(guān)系。

方式一:XML 映射文件 (最強大、最常用)

這是 MyBatis 最傳統(tǒng)也是功能最豐富的映射方式。它遵循兩條黃金法則:

法則1:namespace 必須是 Mapper 接口的全限定名。
這是連接 XML 文件和 Java 接口的“紅線”。

法則2:select/insert/update/delete 等標(biāo)簽的 id 必須與接口中的方法名完全一致。
這是定位到具體 SQL 語句的“門牌號”。

示例:

UserMapper.java (接口定義)

package com.example.mapper;
public interface UserMapper {
    User selectById(Long id);
    void insert(User user);
}

UserMapper.xml (SQL 定義)

<?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.UserMapper">
    <select id="selectById" resultType="com.example.model.User">
        SELECT * FROM users WHERE id = #{id}
    </select>
    <insert id="insert">
        INSERT INTO users(username, email) VALUES(#{username}, #{email})
    </insert>
</mapper>

當(dāng)調(diào)用 UserMapper.selectById() 時,代理對象會精確地找到 namespace 為 com.example.mapper.UserMapper 的 XML 文件中,id 為 selectById 的 <select> 標(biāo)簽,并執(zhí)行其中的 SQL。

方式二:注解 (簡單 SQL 的便捷之選)

對于簡單的 SQL 語句,我們可以完全拋棄 XML,直接在接口方法上使用注解。

示例:

package com.example.mapper;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
public interface UserMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User selectById(Long id);
    @Insert("INSERT INTO users(username, email) VALUES(#{username}, #{email})")
    void insert(User user);
}

這種方式非常直觀,但當(dāng) SQL 變得復(fù)雜,特別是需要動態(tài) SQL(ifforeach等)時,XML 的表現(xiàn)力遠勝于注解。

3. 讓 MyBatis 找到你的 Mapper:掃描與注冊

我們已經(jīng)定義好了映射關(guān)系,但還需要告訴 MyBatis 去哪里“發(fā)現(xiàn)”這些接口和 XML 文件。

在現(xiàn)代 Spring Boot 項目中,這通常通過 mybatis-spring-boot-starter 自動完成,我們只需提供少量配置。

1. @MapperScan 注解 (推薦)
在你的 Spring Boot 主啟動類上,添加 @MapperScan 注解,并指定 Mapper 接口所在的包路徑。

@SpringBootApplication
@MapperScan("com.example.mapper")
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

這個注解會告訴 MyBatis:“請掃描 com.example.mapper 包下的所有接口,并將它們注冊為 Mapper Bean。”

2. @Mapper 注解
你也可以不在啟動類上使用 @MapperScan,而是在每個 Mapper 接口上單獨添加 @Mapper 注解。

@Mapper
public interface UserMapper { ... }

這樣,只要 UserMapper 接口在 Spring Boot 的組件掃描路徑下,它就會被自動發(fā)現(xiàn)。但當(dāng) Mapper 接口很多時,@MapperScan 顯然更方便。

3. XML 文件的位置
默認情況下,MyBatis Spring Boot Starter 會在 classpath 中,尋找與 Mapper 接口同包同名的 XML 文件。

標(biāo)準(zhǔn)的 Maven 項目結(jié)構(gòu):

src/
  main/
    java/
      com/
        example/
          mapper/
            UserMapper.java
    resources/
      com/
        example/
          mapper/
            UserMapper.xml  <-- XML 放在 resources 目錄下,但包結(jié)構(gòu)與 Java 接口保持一致

如果你想把 XML 文件集中存放在另一個地方,可以在 application.yml 中通過 mybatis.mapper-locations 屬性來指定:

mybatis:
  mapper-locations: classpath:mappers/*.xml

4. 常見問題與陷阱

BindingException: Type ... is not known to the MapperRegistry.

含義: “未在 Mapper 注冊表中找到該類型”。

原因: MyBatis 根本沒發(fā)現(xiàn)你的 Mapper 接口。請檢查 @MapperScan 的包路徑是否正確,或者接口上是否漏了 @Mapper 注解。

BindingException: Invalid bound statement (not found): ...

含義: “無效的綁定語句(未找到)”。

原因: 接口找到了,但接口里的方法沒找到對應(yīng)的 SQL。請檢查:

1. XML 的 namespace 是否是接口的全限定名,一個字母都不能錯。

2. XML 標(biāo)簽的 id 是否與方法名完全一致

3. XML 文件是否被構(gòu)建工具(Maven/Gradle)正確地打包進了最終的 jar 文件中。

 XML 文件未被打包:
如果你的 XML 文件放在 src/main/java 目錄下,Maven 默認不會打包 .xml 文件。你需要在 pom.xml 中添加如下配置:

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
</build>

總結(jié)

MyBatis 的接口映射機制,看似“神奇”,實則建立在一套清晰、嚴謹?shù)囊?guī)則之上:

  • 1. 核心是 JDK 動態(tài)代理,它在運行時為你的接口創(chuàng)建了一個實現(xiàn)類。
  • 2. 映射的“鑰匙”是“全限定接口名 + 方法名”
  • 3. 映射關(guān)系可以通過 XML 或注解來定義。
  • 4. @MapperScan 是告知 MyBatis 從哪里開始尋找這些“鑰匙”的入口。

到此這篇關(guān)于MyBatis Mapper 接口是如何找到并執(zhí)行 SQL 的的文章就介紹到這了,更多相關(guān)MyBatis Mapper 接口執(zhí)行 SQL內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論