导读:本期聚焦于Ada创作的《XML Mapper是什么?如何在MyBatis中用它来编写SQL映射文件?》,敬请观看详情。MyBatis之所以能摆脱JDBC繁琐的手工操作,靠的就是Mapper映射机制,而XML Mapper正是其中最经典、最稳定的SQL编写方式。本文将从XML Mapper的基本概念讲起,说明它与注解方式的区别,再逐步演示如何在项目中创建映射文件、配置namespace与接口绑定、编写select、insert、update、delete等常见语句,并深入讲解动态SQL标签的使用技巧。文中还涉及结果映射、参数传递、模糊查询、批量操作等高频开发场景,帮助你系统掌握XML Mapper的完整用法,写出结构清晰、易于维护的数据库访问层代码。

在使用MyBatis框架开发数据访问层时,SQL语句的编写位置一直是一个绕不开的话题。相较于把SQL直接写在接口方法上的注解方式,XML Mapper提供了一种将SQL语句与Java代码彻底分离的方案,它把SQL统一放在扩展名为xml的映射文件里,通过命名空间与Mapper接口绑定,实现接口方法到SQL语句的自动映射。这种方式不仅让SQL的维护更加集中,也为复杂动态SQL的编写提供了强大的标签支持,是企业级项目中最主流的选择。

XML Mapper是什么?如何在MyBatis中用它来编写SQL映射文件?

XML Mapper是什么,它和注解方式有何区别

XML Mapper本质上是一个遵循MyBatis DTD约束的XML文件,文件内部定义了SQL语句、参数映射规则和结果映射规则。每一个XML映射文件通过namespace属性与一个Java接口建立唯一对应关系,接口中定义方法,XML中定义同id的SQL语句,程序运行时MyBatis会为接口生成动态代理对象,调用方法时自动执行对应的SQL并完成结果封装。

注解方式则是把SQL直接写在方法上,例如使用@Select@Update等注解。注解方式适合简单场景,代码量少、直观。但一旦SQL变长、需要拼接动态条件,注解里就要借助<script>标签或者拼接字符串,可读性会迅速下降。而XML方式拥有<if><where><foreach>等原生标签,动态SQL的编写体验远好于注解。此外,SQL集中在XML文件中,数据库调优时只需查找映射文件即可,不必在成百上千个Java文件里搜索字符串。

两者的核心区别可以概括为:注解适合短小固定的SQL,XML适合复杂多变、需要长期维护的业务SQL。实际项目中常见的做法是简单SQL用注解快速搞定,核心业务SQL统一放入XML,两者并不冲突,可以共存于同一个Mapper接口。

如何创建并配置一个XML Mapper映射文件

以一个典型的Spring Boot加MyBatis项目为例,假设项目部署在Windows服务器上,映射文件通常放在src\main\resources\mapper目录下,文件命名习惯为实体名加Mapper.xml,例如UserMapper.xml。首先需要在配置文件中指定扫描路径,在application.yml中配置mybatis.mapper-locations: classpath:mapper/*.xml,同时在启动类或配置类上加@MapperScan注解扫描接口所在的包。

映射文件的根元素是<mapper>,其namespace属性必须填写对应的Mapper接口全限定名。下面是一个完整的示例,展示了增删改查四类语句的基本写法:

<?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">

    <!-- 根据id查询用户,resultType为实体类全限定名或别名 -->
    <select id="selectById" resultType="com.example.entity.User">
        SELECT id, username, email, age
        FROM t_user
        WHERE id = #{id}
    </select>

    <!-- 新增用户,useGeneratedKeys回填自增主键 -->
    <insert id="insertUser" parameterType="com.example.entity.User"
            useGeneratedKeys="true" keyProperty="id">
        INSERT INTO t_user (username, email, age)
        VALUES (#{username}, #{email}, #{age})
    </insert>

    <!-- 更新用户 -->
    <update id="updateUser" parameterType="com.example.entity.User">
        UPDATE t_user
        SET username = #{username}, email = #{email}, age = #{age}
        WHERE id = #{id}
    </update>

    <!-- 删除用户 -->
    <delete id="deleteById" parameterType="long">
        DELETE FROM t_user WHERE id = #{id}
    </delete>
</mapper>

对应的Java接口只需要声明方法,不需要任何实现类:

package com.example.mapper;

import com.example.entity.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;

public interface UserMapper {
    User selectById(Long id);
    int insertUser(User user);
    int updateUser(User user);
    int deleteById(Long id);
}

需要注意几个细节。第一,SQL语句的id必须与接口方法名完全一致,包括大小写。第二,#{}是预编译占位符,会被转换为JDBC的PreparedStatement参数,能有效防止SQL注入;而${}是字符串直接拼接,只应用于动态表名、排序字段这类无法预编译的场景,且必须校验来源。第三,如果方法有多个参数,建议使用@Param注解为每个参数命名,否则只能通过arg0、param1这类系统默认名称引用。

动态SQL与高级结果映射的实战用法

动态SQL是XML Mapper最强大的能力。多条件查询时,用户可能只填部分筛选项,使用<where>配合<if>可以自动处理where关键字和多余的and前缀:

<select id="selectByCondition" resultType="com.example.entity.User">
    SELECT id, username, email, age
    FROM t_user
    <where>
        <if test="username != null and username != ''">
            AND username LIKE CONCAT('%', #{username}, '%')
        </if>
        <if test="minAge != null">
            AND age >= #{minAge}
        </if>
        <if test="maxAge != null">
            AND age <= #{maxAge}
        </if>
    </where>
</select>

批量操作则依赖<foreach>标签,它可以遍历集合生成in条件或者批量插入的values片段。下面的例子演示批量插入一千条数据时的高效写法,比循环调用单条insert快一个数量级:

<insert id="batchInsert">
    INSERT INTO t_user (username, email, age) VALUES
    <foreach collection="list" item="u" separator=",">
        (#{u.username}, #{u.email}, #{u.age})
    </foreach>
</insert>

当数据库字段名与实体属性名不一致,或者存在一对一、一对多关联关系时,就需要用到<resultMap>。它先定义列到属性的映射规则,再通过<association><collection>处理关联对象。例如订单与用户是一对一、订单与订单明细是一对多:

<resultMap id="orderResultMap" type="com.example.entity.Order">
    <id property="id" column="order_id"/>
    <result property="orderNo" column="order_no"/>
    <association property="user" javaType="com.example.entity.User">
        <id property="id" column="user_id"/>
        <result property="username" column="username"/>
    </association>
    <collection property="items" ofType="com.example.entity.OrderItem">
        <id property="id" column="item_id"/>
        <result property="productName" column="product_name"/>
    </collection>
</resultMap>

此外还有一些提升可维护性的技巧:用<sql>标签抽取重复的字段列表,用<include>在多处引用;写update语句时配合<set>标签自动剔除末尾逗号,实现只更新非空字段。排查问题时可在配置中开启SQL日志输出,观察实际执行的语句与参数是否正确。掌握这些用法后,XML Mapper足以应对绝大多数持久层开发需求,既保证了SQL的灵活性,又维持了代码结构的清晰整洁。

XML MapperMyBatisSQL映射修改时间:2026-08-31 19:21:05

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。