树码科技 | 技术博客

MyBatis 映射配置文件

2026/04/10
62
0

引言

在 MyBatis Plus 中,mapper.xml 是核心的 SQL 映射配置文件,用于编写自定义 SQL 语句,实现复杂的数据库增、删、改、查操作。相比 MyBatis Plus 提供的通用 CRUD 方法,XML 文件支持动态 SQL、多表关联、复杂查询等场景,能完美适配多样化的业务逻辑。

基本配置

MyBatis Plus 整合 XML 映射文件的核心是配置扫描路径,确保框架能加载到自定义的 XML 文件,完成接口与 SQL 的绑定。

YAML 配置

在 application.yml 中配置 Mapper XML 的扫描路径,这是框架加载 XML 的核心配置:

mybatis-plus:
  # 配置 Mapper XML 文件的扫描路径
  mapper-locations: classpath*:/mapper/**/*.xml
  # 【补全】配置实体类别名包,简化 XML 中 resultType 写法
  type-aliases-package: com.lusifer.boot.domain

配置说明

  1. mapper-locations:指定 XML 文件的存放位置,classpath* 表示扫描所有模块(多模块 Maven 项目必须加),/mapper/**/*.xml 匹配 mapper 目录下所有子目录的 XML 文件;

  2. type-aliases-package:为实体类配置别名,后续 XML 中可直接使用类名,无需书写全限定类名。

XML 文件创建

在项目的 src/main/resources/mapper 目录下,创建与 Mapper 接口同名的 XML 文件(示例:UserMapper.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 接口的全限定类名 -->
<mapper namespace="com.lusifer.boot.mapper.UserMapper">
    <!-- 自定义查询语句:根据 ID 查询用户 -->
    <select id="findById" resultType="User">
        SELECT * FROM user WHERE id = #{id}
    </select>
</mapper>

标签说明

  1. DOCTYPE:声明 XML 约束,必须保留,否则框架无法识别标签;

  2. <mapper>:根标签,namespace 是唯一绑定标识,必须与 Mapper 接口全类名一致;

  3. <select>:查询标签,对应 SELECT 语句,新增/修改/删除分别对应 <insert>/<update>/<delete>。

接口定义

创建 Mapper 接口,继承 MyBatis Plus 的 BaseMapper,并声明与 XML 中 id 一致的方法:

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lusifer.boot.domain.User;

@Mapper
public interface UserMapper extends BaseMapper<User> {

    /**
     * 根据 ID 查询用户(与 XML 中 id="findById" 对应)
     * @param id 用户 ID
     * @return 用户实体
     */
    User findById(@Param("id") Long id);
}

注解说明

  1. @Mapper:让 Spring 扫描并创建 Mapper 接口的代理对象;也可在启动类添加 @MapperScan("com.lusifer.boot.mapper") 统一扫描;

  2. @Param("id"):指定参数名称,与 XML 中 #{id} 对应,多参数场景必须添加。

单元测试

编写测试用例,调用自定义的 XML 方法,验证功能是否正常:

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class UserMapperTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testFindById() {
        // 调用 XML 中定义的自定义方法
        User user = userMapper.findById(1L);
        System.out.println("查询结果:" + user);
    }
}

映射配置文件

Mapper XML 是 MyBatis 的核心配置文件,负责Java 对象与数据库数据的映射,包含参数映射、结果映射两大核心功能。

文件命名

  1. 命名规则:XML 文件名与对应 Mapper 接口完全一致(如 UserMapper.java 对应 UserMapper.xml);

  2. 存放规范:推荐放在 resources/mapper 目录下,与 Mapper 接口的包结构形成对应,便于维护。

参数映射

参数映射用于将 Java 方法的参数传递到 SQL 语句中,MyBatis 提供 #{} 和 ${} 两种占位符,用法与安全性差异极大。

#{} 占位符(推荐)

  • 替换机制:SQL 预编译阶段替换为 ? 占位符,自动处理参数转义、类型转换;

  • 核心优势:防止 SQL 注入,是业务开发的首选;

  • 适用场景:所有普通参数(数值、字符串、日期等)。

<select id="findByName" resultType="User">
    SELECT * FROM user WHERE username = #{username}
</select>

${} 占位符

  • 替换机制:SQL 执行前直接字符串拼接,无预编译处理;

  • 核心风险:存在 SQL 注入漏洞;

  • 适用场景:仅用于动态传入表名、列名、排序字段等非数据参数。

<select id="findByColumn" resultType="User">
    SELECT * FROM user WHERE ${columnName} = #{columnValue}
</select>

核心区别

占位符

执行时机

安全性

适用场景

#{}

预编译阶段

安全,防注入

普通业务参数

${}

字符串拼接

不安全

表名、列名、排序字段

结果映射

将数据库查询结果映射为 Java 实体对象,支持 resultType 和 resultMap 两种方式。

resultType

简单映射

直接指定返回的实体类型(配合别名配置,可直接写类名),适用于字段名完全匹配的场景:

<select id="findAll" resultType="User">
    SELECT * FROM user
</select>

resultMap

自定义映射

适用于字段名不匹配、多表关联查询、嵌套对象等复杂场景,手动配置列与属性的映射关系:

<!-- 定义结果映射规则 -->
<resultMap id="userResultMap" type="User">
    <!-- 主键映射 -->
    <id column="id" property="id"/>
    <!-- 普通字段映射:column=数据库列名,property=实体属性名 -->
    <result column="user_name" property="username"/>
    <result column="create_time" property="createTime"/>
</resultMap>

<!-- 使用自定义 resultMap -->
<select id="findById" resultMap="userResultMap">
    SELECT id, user_name, create_time FROM user WHERE id = #{id}
</select>

动态 SQL

动态 SQL 是 MyBatis 的核心特性,通过标签拼接 SQL 语句,实现根据参数动态生成条件,无需手动拼接字符串。

If 标签

基础条件判断,满足条件则拼接对应的 SQL 片段:

<select id="findUserByCondition" resultType="User">
    SELECT * FROM user
    <where>
        <if test="id != null">AND id = #{id}</if>
        <if test="username != null and username != ''">AND username = #{username}</if>
        <if test="age != null">AND age = #{age}</if>
    </where>
</select>

标签说明

<where>:自动去除开头多余的 AND/OR,避免 SQL 语法错误。

Choose When Otherwise

等效于 Java 的 switch-case,多选一执行条件:

<select id="findUserByChoose" resultType="User">
    SELECT * FROM user
    <where>
        <choose>
            <when test="username != null">AND username = #{username}</when>
            <when test="email != null">AND email = #{email}</when>
            <!-- 所有条件都不满足时执行 -->
            <otherwise>AND status = 1</otherwise>
        </choose>
    </where>
</select>

Set 标签

专用于 UPDATE 语句,自动去除结尾多余的逗号,避免语法错误:

<update id="updateUser">
    UPDATE user
    <set>
        <if test="username != null">username = #{username},</if>
        <if test="age != null">age = #{age},</if>
    </set>
    WHERE id = #{id}
</update>

Foreach 标签

用于批量操作(批量查询、批量插入、批量删除),遍历集合/数组:

<!-- 批量根据 ID 查询用户 -->
<select id="findByIds" resultType="User">
    SELECT * FROM user WHERE id IN
    <foreach collection="ids" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</select>

属性说明

  • collection:遍历的集合/数组名称;

  • item:遍历的每一个元素;

  • open/close:拼接的开头/结尾字符;

  • separator:元素之间的分隔符。

特殊字符处理

XML 语法中,<、>、& 等字符属于保留字符,直接写在 SQL 中会报错,需通过两种方式处理。

转义字符

使用 XML 预定义的转义字符替换特殊符号:

特殊字符

转义字符

含义

<

<

小于

>

>

大于

&

&

和

"

"

双引号

'

'

单引号

示例:

<select id="findByAge" resultType="User">
    SELECT * FROM user WHERE age &gt; #{minAge} AND age &lt; #{maxAge}
</select>

CDATA 块

将 SQL 语句放在 <![CDATA[ ]]> 块中,忽略所有特殊字符解析,适合复杂条件:

<select id="findByAge" resultType="User">
    <![CDATA[
        SELECT * FROM user WHERE age > #{minAge} AND age < #{maxAge}
    ]]>
</select>

注意事项

CDATA 块内不支持动态 SQL 标签(如 <if>、<where>),仅用于纯 SQL 片段。

常见问题

  1. XML 文件找不到 原因:mapper-locations 配置错误,或 XML 文件未放在 resources/mapper 目录; 解决方案:检查路径配置,确保 classpath*:/mapper/**/*.xml 匹配文件位置。

  2. 方法绑定失败 原因:XML 中 id 与接口方法名不一致,或 namespace 与接口全类名不匹配; 解决方案:严格保证名称一致。

  3. 参数无效 原因:未加 @Param 注解,或 XML 中占位符名称与参数名不一致; 解决方案:多参数场景必须添加 @Param 注解。

  4. SQL 注入风险 原因:滥用 ${} 占位符; 解决方案:业务参数统一使用 #{} 。

总结

  1. 整合 MyBatis Plus 与 XML 的核心是配置 mapper-locations,多模块项目必须使用 classpath*;

  2. 参数映射优先用 #{} 保证安全,${} 仅用于动态表名/列名;

  3. 结果映射简单场景用 resultType,复杂场景用 resultMap;

  4. 动态 SQL 常用 <if>、<where>、<set>、<foreach> 标签,灵活拼接条件;

  5. XML 特殊字符优先用转义字符,复杂 SQL 可使用 CDATA 块。