1. Mybatis-Plus与XML的协作模式解析
Mybatis-Plus作为Mybatis的增强工具,在保留原生Mybatis所有特性的基础上,提供了更多便捷功能。虽然Mybatis-Plus推崇"约定优于配置"的理念,通过注解和Wrapper条件构造器就能完成大部分CRUD操作,但在复杂业务场景下,XML映射文件仍然是不可替代的方案。
XML方式的核心优势在于:
- 支持动态SQL的灵活组装(if/choose/when/otherwise等标签)
- 便于管理超长SQL语句(特别是多表关联查询)
- 实现特殊语法需求(如数据库方言差异处理)
- 方便DBA参与SQL优化(直接查看XML文件即可)
实际项目中常见的混合使用模式是:简单CRUD用Mybatis-Plus的BaseMapper+Wrapper,复杂查询/统计报表用XML映射。这种组合既能享受Mybatis-Plus的便捷,又能应对复杂SQL需求。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. XML映射文件的基础配置
2.1 文件位置与命名规范
XML映射文件默认应存放在resources/mapper目录下,与Mapper接口保持同名。例如:
code复制src/main/java/com/example/mapper/UserMapper.java
src/main/resources/mapper/UserMapper.xml
文件基础结构示例:
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 namespace="com.example.mapper.UserMapper">
<!-- SQL定义区域 -->
</mapper>
关键注意事项:
- namespace必须对应Mapper接口的全限定名
- 建议每个XML文件只处理一个实体类的相关SQL
- 文件名与接口名严格一致(区分大小写)
2.2 与Mybatis-Plus的配置整合
在Spring Boot的application.yml中需要显式指定mapper-locations:
yaml复制mybatis-plus:
mapper-locations: classpath:mapper/**/*.xml
configuration:
map-underscore-to-camel-case: true # 自动驼峰转换
提示:如果同时使用注解和XML方式,需要确保方法名不重复,否则会报"Ambiguous mapping"错误
3. XML中的SQL编写实战
3.1 基础CRUD的XML实现
虽然Mybatis-Plus的BaseMapper已经提供了通用CRUD方法,但通过XML可以更灵活地定制:
xml复制<!-- 根据ID查询(带结果映射) -->
<select id="selectById" resultType="com.example.entity.User">
SELECT * FROM user WHERE id = #{id}
</select>
<!-- 条件查询(参数为Map) -->
<select id="selectByMap" resultType="com.example.entity.User">
SELECT * FROM user
<where>
<if test="name != null">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>
3.2 动态SQL的高级用法
XML最强大的特性就是动态SQL构建:
xml复制<!-- 多条件更新 -->
<update id="updateSelective">
UPDATE user
<set>
<if test="name != null">name=#{name},</if>
<if test="email != null">email=#{email},</if>
<if test="status != null">status=#{status},</if>
</set>
WHERE id=#{id}
</update>
<!-- 批量插入 -->
<insert id="batchInsert">
INSERT INTO user (name, age) VALUES
<foreach collection="list" item="item" separator=",">
(#{item.name}, #{item.age})
</foreach>
</insert>
3.3 分页查询的两种实现
方式一:配合Mybatis-Plus的Page对象(推荐)
xml复制<select id="selectPage" resultType="com.example.entity.User">
SELECT * FROM user
<where>
<if test="params.name != null">
AND name LIKE CONCAT('%',#{params.name},'%')
</if>
</where>
</select>
方式二:使用数据库方言(MySQL示例)
xml复制<select id="selectByPage" resultType="com.example.entity.User">
SELECT * FROM user
LIMIT #{offset}, #{pageSize}
</select>
4. 与Mybatis-Plus特性的深度结合
4.1 自动填充字段处理
Mybatis-Plus的@TableField(fill = FieldFill.INSERT)等注解可以与XML完美配合:
xml复制<insert id="customInsert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user
(name, age, create_time, update_time)
VALUES
(#{name}, #{age}, #{createTime}, #{updateTime})
</insert>
4.2 逻辑删除的XML实现
配置了逻辑删除后,XML中的SQL无需特殊处理删除语句,Mybatis-Plus会自动注入条件:
xml复制<select id="selectActiveUsers" resultType="com.example.entity.User">
SELECT * FROM user WHERE deleted = 0
<!-- 其他条件 -->
</select>
4.3 多租户支持
通过Mybatis-Plus的TenantLineInnerInterceptor,XML中的SQL会自动添加租户条件:
xml复制<select id="selectByTenant" resultType="com.example.entity.User">
SELECT * FROM user
<!-- 自动添加 tenant_id = ? 条件 -->
</select>
5. 性能优化与疑难解答
5.1 XML缓存机制
Mybatis的XML映射文件会被解析为MappedStatement对象缓存起来:
- 一级缓存:SqlSession级别(默认开启)
- 二级缓存:Mapper级别(需要显式配置)
启用二级缓存示例:
xml复制<mapper namespace="com.example.mapper.UserMapper">
<cache eviction="LRU" flushInterval="60000"/>
<!-- SQL定义 -->
</mapper>
5.2 常见问题排查
-
XML文件未加载:
- 检查mapper-locations配置路径
- 确认文件在target目录中存在(Maven资源过滤问题)
-
SQL执行报错:
- 使用Mybatis-Plus的SQL注入器打印最终SQL
java复制
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl -
动态SQL不生效:
- 检查参数是否为null(注意基本类型默认值问题)
- 测试时使用明确的参数Map
5.3 开发效率技巧
-
IDEA智能提示:
安装MyBatisX插件,可以实现:- XML与Mapper接口的跳转
- SQL语法检查
- 代码自动补全
-
SQL格式化:
使用快捷键(Ctrl+Alt+L)保持SQL可读性:xml复制<select id="complexQuery"> SELECT u.*, d.dept_name FROM user u LEFT JOIN department d ON u.dept_id = d.id <where> <if test="role != null"> AND u.role = #{role} </if> </where> ORDER BY u.create_time DESC </select> -
XML与注解的混合使用:
java复制public interface UserMapper extends BaseMapper<User> { @Select("SELECT count(*) FROM user") int countAll(); List<User> selectComplex(@Param("params") Map<String, Object> params); // XML实现 }
6. 企业级最佳实践
6.1 大型项目中的XML管理
-
按业务模块拆分:
code复制resources/ ├── mapper/ │ ├── order/ │ │ ├── OrderMapper.xml │ │ └── OrderItemMapper.xml │ └── user/ │ ├── UserMapper.xml │ └── RoleMapper.xml -
SQL复用机制:
xml复制<!-- 定义可复用的SQL片段 --> <sql id="baseColumns">id, name, email, status</sql> <select id="selectAll" resultType="com.example.entity.User"> SELECT <include refid="baseColumns"/> FROM user </select>
6.2 安全防护方案
-
SQL注入防护:
- 永远使用#{}而非${}(除非必要场景)
- 对like查询做特殊处理:
xml复制<if test="name != null"> AND name LIKE CONCAT('%', #{name}, '%') </if> -
敏感数据加密:
结合Mybatis-Plus的字段加密功能:xml复制<insert id="insertUser"> INSERT INTO user (name, mobile) VALUES (#{name}, #{mobile}) <!-- 自动加密 --> </insert>
6.3 监控与调优
-
慢SQL监控:
xml复制<!-- 在开发环境添加SQL注释 --> <select id="selectComplexData"> /* 业务说明:用户综合查询 */ SELECT ... FROM ... </select> -
执行计划分析:
通过EXPLAIN验证复杂SQL:xml复制<select id="explainQuery"> EXPLAIN SELECT * FROM large_table WHERE create_time > #{startDate} </select>
在实际项目开发中,我通常会建立这样的开发流程:先使用Mybatis-Plus的快速开发功能搭建基础框架,随着业务复杂度的提升,逐步将复杂SQL迁移到XML中。特别是在需要DBA参与SQL优化的企业环境中,XML方式更便于跨团队协作。一个实用的建议是:即使当前使用注解方式足够简单,也建议提前规划好XML的目录结构,因为几乎所有项目最终都会需要XML来处理某些复杂场景。
