[笔记] MyBatis-Plus XML 配置详解:从基础到高级,全面提升开发效率

MyBatis-Plus 是一个 MyBatis 的增强工具,旨在简化开发过程,提供更便捷的数据库操作方式。在 MyBatis-Plus 中,XML 配置文件扮演着重要的角色,它允许开发者定义 SQL 语句、映射结果集以及配置各种数据库操作。本文将详细介绍 MyBatis-Plus XML 配置文件中的各种标签和功能,从基础的查询、插入、更新、删除操作,到高级的动态 SQL、结果映射和批量操作,帮助你全面掌握 MyBatis-Plus 的 XML 配置技巧,提升开发效率。(主要就是因为 mybatis-plus 封装的太好了,能不写sql就不写,到写的时候都忘记了...)

MyBatis-Plus 官网 : Mybatis-Plus
MyBatis 官网 : Mybatis中文官网

SQL 优化 :[笔记] SQL数据库优化实战 : SQL 全面优化本文总结了SQL数据库优化的实战技巧,包括字段选择、索引策略、查询语... - 掘金


一. 基础标签

1. select 标签

xml 复制代码
<select id="getById" resultType="User" parameterType="long">
    SELECT * FROM user WHERE id = #{id}
</select>

用于查询操作,最基本的查询标签。

  • id: 对应 Mapper 接口中的方法名。
  • resultType: 返回的结果类型。
  • parameterType: 参数类型(可选)。

2. insert 标签

xml 复制代码
<insert id="insert" parameterType="User" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO user (username, age) VALUES (#{username}, #{age})
</insert>

用于插入操作。

  • useGeneratedKeys: 是否使用自增主键。
  • keyProperty: 自增主键对应的属性名。

3. update 标签

xml 复制代码
<update id="update" parameterType="User">
    UPDATE user SET username = #{username} WHERE id = #{id}
</update>

用于更新操作。

  • parameterType: 参数类型。

4. delete 标签

xml 复制代码
<delete id="deleteById" parameterType="long">
    DELETE FROM user WHERE id = #{id}
</delete>

用于删除操作。

  • parameterType: 参数类型。

二. 动态 SQL 标签

1. if 标签

xml 复制代码
<if test="username != null and username != ''">
    AND username LIKE CONCAT('%', #{username}, '%')
</if>

条件判断,当 test 属性中的条件成立时,才会将其包含的 SQL 片段拼接到最终的 SQL 中。

  • test: 判断条件,支持 OGNL 表达式

2. choose-when-otherwise 标签

xml 复制代码
<choose>
    <when test="status != null">
        AND status = #{status}
    </when>
    <when test="type != null">
        AND type = #{type}
    </when>
    <otherwise>
        AND create_time > SYSDATE
    </otherwise>
</choose>

类似 Java 中的 switch 语句,只会执行一个条件。

3. where 标签

xml 复制代码
<where>
    <if test="username != null">
        AND username = #{username}
    </if>
    <if test="age != null">
        AND age >= #{age}
    </if>
</where>

自动处理 WHERE 子句,会自动去除多余的 ANDOR

4. set 标签

xml 复制代码
<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>

用在 UPDATE 语句中,自动处理 SET 关键字和逗号。

5. trim 标签

xml 复制代码
<trim prefix="WHERE" prefixOverrides="AND|OR" suffix=")" suffixOverrides=",">
    <if test="username != null">
        AND username = #{username},
    </if>
</trim>

更灵活的前缀/后缀处理。

  • prefix: 给整个语句增加前缀。
  • prefixOverrides: 去除整个语句前面的关键字或字符。
  • suffix: 给整个语句增加后缀。
  • suffixOverrides: 去除整个语句后面的关键字或字符。
  • 运行结果 : WHERE username = #{username}

6. foreach 标签

xml 复制代码
<foreach collection="list" item="item" index="index" open="(" separator="," close=")">
    #{item}
</foreach>

循环遍历集合或数组。

  • collection: 要遍历的集合或数组(listarraymap等)。
  • item: 当前遍历的元素。
  • index: 当前遍历的索引。
  • open: 开始字符。
  • separator: 分隔符。
  • close: 结束字符。

三. 高级映射

1. resultMap 标签

xml 复制代码
<resultMap id="UserResultMap" type="User">
    <!-- 主键映射 -->
    <id property="id" column="user_id"/>
    
    <!-- 普通属性映射 -->
    <result property="username" column="user_name"/>
    
    <!-- 一对一关系 -->
    <association property="profile" javaType="UserProfile">
        <id property="id" column="profile_id"/>
        <result property="address" column="address"/>
    </association>
    
    <!-- 一对多关系 -->
    <collection property="roles" ofType="Role">
        <id property="id" column="role_id"/>
        <result property="roleName" column="role_name"/>
    </collection>
</resultMap>

自定义结果映射关系。

  • <resultMap>标签
    • id="UserResultMap": 定义了这个 <resultMap> 的唯一标识符,以便在其他地方引用它。
    • type="User": 指定了这个 <resultMap> 所映射的目标类型,这里是 User 类。

  • 主键映射
    • <id property="id" column="user_id"/>: 映射数据库表中的 user_id 列到 User 对象的 id 属性上。<id> 标签通常用于主键映射,有助于提高 MyBatis 在处理关联关系时的性能。

  • 普通属性映射
    • <result property="username" column="user_name"/>: 将数据库表中的 user_name 列映射到 User 对象的 username 属性上。<result> 标签用于普通属性的映射。

  • 一对一关系 (<association>)
    • property="profile" javaType="UserProfile": 表示 User 对象与 UserProfile 对象之间存在一对一的关系,并且将查询结果映射到 User 对象的 profile 属性上。
      • <id property="id" column="profile_id"/>: 映射 UserProfile 对象的主键。
      • <result property="address" column="address"/>: 映射 UserProfile 对象的 address 属性。

  • 一对多关系 (<collection>)
    • property="roles" ofType="Role": 表示 User 对象与多个 Role 对象之间存在一对多的关系,并且将查询结果映射到 User 对象的 roles 属性上。
      • <id property="id" column="role_id"/>: 映射每个 Role 对象的主键。
      • <result property="roleName" column="role_name"/>: 映射每个 Role 对象的 roleName 属性。

2. sql 标签

xml 复制代码
<!-- 定义 SQL 片段 -->
<sql id="Base_Column_List">
    id, username, age, email, create_time
</sql>

<!-- 使用 SQL 片段 -->
<select id="selectById">
    SELECT <include refid="Base_Column_List"/> FROM user
</select>

定义可重用的 SQL 片段。


四. 特殊功能

1. bind 标签

xml 复制代码
<select id="selectByName">
    <bind name="pattern" value="'%' + name + '%'"/>
    SELECT * FROM user WHERE username LIKE #{pattern}
</select>

创建一个变量并绑定到上下文中。

2. 特殊字符:CDATA 区段(关联 XML 实体)

xml 复制代码
<select id="getUsers">
    SELECT * FROM user
    WHERE age <![CDATA[ >= ]]> #{minAge}
</select>

处理特殊字符。

3. 特殊字符:XML 实体(关联 CDATA 区段)

  • 预定义的 XML 实体
xml 复制代码
<select id="getUsers">
    SELECT * FROM user
    WHERE age &gt;= #{minAge}
</select>

预定义的 XML 实体

  • < 对应 &lt;
  • > 对应 &gt;
  • & 对应 &amp;
  • " 对应 &quot;
  • ' 对应 '
  • 自定义实体
xml 复制代码
<!-- DOCTYPE声明 -->
<!DOCTYPE example [
    <!ENTITY myEntity "This is a custom entity">
]>

<!-- 使用 -->
<example>
    Here is the custom entity: &myEntity;
</example>

<!-- 结果 -->
<example>
    Here is the custom entity: This is a custom entity
</example>

自定义实体允许你在XML文档中定义一些简短的替代符号,这些符号可以在文档的不同部分引用。

代码解释

  • <!DOCTYPE example [...] >: 这是一个DOCTYPE声明,用于定义当前文档的类型和结构。在这个例子中,example是根元素名称,方括号[]内包含了自定义实体的定义。
  • <!ENTITY myEntity "This is a custom entity">: 定义了一个名为myEntity的自定义实体。myEntity是一个标识符,"This is a custom entity"是这个实体的实际值。在文档的其他地方,你可以通过&myEntity;来引用这个实体。
  • <example>: 根元素,包含文档的主要内容。
  • Here is the custom entity: &myEntity;: 在这个元素的内容中,使用了之前定义的自定义实体&myEntity;。当解析器读取到这个标记时,会自动将其替换为实体的实际值"This is a custom entity"

渲染结果

当你解析这个XML文档时,解析器会将&myEntity;替换为其定义的值。最终的结果将是:

xml 复制代码
<example>
    Here is the custom entity: This is a custom entity
</example>

五. 实用场景示例

1. 动态表关联

xml 复制代码
<select id="getUserDetails" resultMap="UserDetailMap">
    SELECT u.* 
    FROM user u
    <!-- 动态关联用户资料表 -->
    <if test="includeProfile">
        LEFT JOIN user_profile up ON u.id = up.user_id
    </if>
    <!-- 动态关联角色表 -->
    <if test="includeRoles">
        LEFT JOIN user_role ur ON u.id = ur.user_id
        LEFT JOIN role r ON ur.role_id = r.id
    </if>
    WHERE u.id = #{userId}
</select>

根据条件决定是否关联其他表。

动态地从多个表中获取用户详细信息。

代码解析

  • <select id="getUserDetails" resultMap="UserDetailMap"> : 定义了这个查询的唯一标识符,可以在Java代码中通过这个ID来调用该查询,并指定了结果映射(resultMap)。

  • SELECT u.* FROM user u : 选择了user表中的所有列,并给这个表起了一个别名u

  • 动态关联用户资料表:

    xml 复制代码
    <if test="includeProfile">
        LEFT JOIN user_profile up ON u.id = up.user_id
    </if>
    • 检查传入的参数includeProfile是否为true。如果为true,则执行内部的SQL片段。
  • 动态关联角色表:

    xml 复制代码
    <if test="includeRoles">
        LEFT JOIN user_role ur ON u.id = ur.user_id
        LEFT JOIN role r ON ur.role_id = r.id
    </if>
    • 检查传入的参数includeRoles是否为true。如果为true,则执行内部的SQL片段。
  • WHERE u.id = #{userId}: 这条语句用于过滤结果,只返回指定用户ID的数据。


调用

传参:

  • includeProfile = true
  • includeRoles = true
  • userId = 1

生成的SQL:

sql 复制代码
SELECT u.* 
FROM user u
LEFT JOIN user_profile up ON u.id = up.user_id
LEFT JOIN user_role ur ON u.id = ur.user_id
LEFT JOIN role r ON ur.role_id = r.id
WHERE u.id  

2. 批量操作优化

xml 复制代码
<!-- MySQL批量更新 -->
<update id="batchUpdate">
    UPDATE user
    <trim prefix="SET" suffixOverrides=",">
        <trim prefix="username = CASE" suffix="END,">
            <foreach collection="list" item="item">
                WHEN id = #{item.id} THEN #{item.username}
            </foreach>
        </trim>
    </trim>
    WHERE id IN
    <foreach collection="list" item="item" open="(" separator="," close=")">
        #{item.id}
    </foreach>
</update>

适用于大量数据的批量操作。

批量更新用户表中的数据。

代码解析

  • <update id="batchUpdate">: 定义了这个更新操作的唯一标识符,可以在Java代码中通过这个ID来调用该更新操作。

  • UPDATE user : 指定了要更新的表名,这里是user表。

  • 第一个 <trim> 标签:

    xml 复制代码
    <trim prefix="SET" suffixOverrides=",">
        ...
    </trim>
    • prefix="SET" : 在生成的SQL语句前添加SET关键字。
    • suffixOverrides=",": 自动移除生成的SQL语句末尾多余的逗号。
  • 第二个 <trim> 标签:

    xml 复制代码
    <trim prefix="username = CASE" suffix="END,">
        ...
    </trim>
    • prefix="username = CASE" : 在生成的SQL语句前添加username = CASE
    • suffix="END," : 在生成的SQL语句后添加END,
  • 嵌套的 <foreach> 标签:

    xml 复制代码
    <foreach collection="list" item="item">
        WHEN id = #{item.id} THEN #{item.username}
    </foreach>
    • collection="list": 指定要遍历的集合,这里假设传入的参数是一个包含多个用户的列表。
    • item="item" : 定义当前遍历项的变量名,这里是item
  • WHERE id IN ...:

    xml 复制代码
    WHERE id IN
    <foreach collection="list" item="item" open="(" separator="," close=")">
        #{item.id}
    </foreach>
    • 这部分使用另一个<foreach>标签来生成WHERE id IN (...)子句。

整体效果

假设你传入的参数是一个包含两个用户的列表,每个用户都有一个id和一个新的username值:

java 复制代码
List<User> userList = new ArrayList<>();
userList.add(new User(1, "newUsername1"));
userList.add(new User(2, "newUsername2"));

生成的最终SQL语句将会是:

sql 复制代码
UPDATE user 
SET username = CASE 
    WHEN id = 1 THEN 'newUsername1' 
    WHEN id = 2 THEN 'newUsername2' 
END 
WHERE id IN (1, 2);

六. 最佳实践

1. 性能优化

  • 避免使用 SELECT *,只查询需要的字段。
  • 合理使用索引。
  • 大量数据操作时使用批量处理。
  • 适当使用缓存。

2. 安全性

  • 使用 #{} 而不是 ${} 来防止 SQL 注入。
  • 参数校验。
  • 敏感数据加密。

3. 可维护性

  • 使用统一的命名规范
  • 添加适当的注释
  • 复杂 SQL 进行模块化处理
  • 保持代码整洁和可读性

七. 注意事项

  1. #{}${} 的区别:
    • #{} 会进行预编译,防止 SQL 注入。
    • ${} 直接替换,有 SQL 注入风险。
  2. 动态 SQL 的顺序很重要,要注意逻辑的先后顺序。
  3. 批量操作时注意数据库的性能限制。
  4. 复杂查询建议使用 resultMap 而不是 resultType
  5. 对于大量重复的 SQL 片段,建议使用 sql 标签复用。

相关推荐
uhakadotcom12 分钟前
Apache APISIX 简介与实践
后端·面试·github
Asthenia041214 分钟前
面试官问“epoll的原理”,我该怎么回答?
后端
uhakadotcom15 分钟前
Kong Gateway 简介与实践
后端·面试·github
潘多编程23 分钟前
Spring Boot分布式项目实战:装饰模式的正确打开方式
spring boot·分布式·后端
uhakadotcom24 分钟前
Apache SkyWalking:分布式系统的可观测性平台
后端·面试·github
uhakadotcom28 分钟前
RocketMQ:解密阿里巴巴都在用的高性能消息队列
后端·面试·github
uhakadotcom29 分钟前
Apache Beam:统一的大数据处理模型
后端·面试·github
uhakadotcom29 分钟前
Apache Superset:现代化数据分析与可视化平台
后端·面试·github
Lvan32 分钟前
程序员必看:两个思想优化90%的代码
java·后端
失业写写八股文32 分钟前
分布式事务深度解析:从理论到实践
分布式·后端·微服务