源本科技 | 码上会

MyBatis 映射配置文件

2026/04/10
1
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 实体对象,支持 resultTyperesultMap 两种方式。

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 块。