当前位置: 首页 > article >正文

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

文章目录

  • 一. 基础标签
    • 1. select 标签
    • 2. insert 标签
    • 3. update 标签
    • 4. delete 标签
  • 二. 动态 SQL 标签
    • 1. if 标签
    • 2. choose-when-otherwise 标签
    • 3. where 标签
    • 4. set 标签
    • 5. trim 标签
    • 6. foreach 标签
  • 三. 高级映射
    • 1. resultMap 标签
    • 2. sql 标签
  • 四. 特殊功能
    • 1. bind 标签
    • 2. 特殊字符:CDATA 区段(关联 XML 实体)
    • 3. 特殊字符:XML 实体(关联 CDATA 区段)
  • 五. 实用场景示例
    • 1. 动态表关联
    • 2. 批量操作优化
  • 六. 最佳实践
    • 1. 性能优化
    • 2. 安全性
    • 3. 可维护性
  • 七. 注意事项


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 全面优化


一. 基础标签

1. select 标签

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

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

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

2. insert 标签

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

用于插入操作。

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

3. update 标签

<update id="update" parameterType="User">
    UPDATE user SET username = #{username} WHERE id = #{id}
</update>

用于更新操作。

  • parameterType: 参数类型。

4. delete 标签

<delete id="deleteById" parameterType="long">
    DELETE FROM user WHERE id = #{id}
</delete>

用于删除操作。

  • parameterType: 参数类型。

二. 动态 SQL 标签

1. if 标签

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

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

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

2. choose-when-otherwise 标签

<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 标签

<where>
    <if test="username != null">
        AND username = #{username}
    </if>
    <if test="age != null">
        AND age >= #{age}
    </if>
</where>

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

4. set 标签

<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 标签

<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 标签

<foreach collection="list" item="item" index="index" open="(" separator="," close=")">
    #{item}
</foreach>

循环遍历集合或数组。

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

三. 高级映射

1. resultMap 标签

<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 标签

<!-- 定义 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 标签

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

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

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

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

处理特殊字符。

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

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

预定义的 XML 实体

  • < 对应 &lt;
  • > 对应 &gt;
  • & 对应 &amp;
  • " 对应 &quot;
  • ' 对应 &apos;
  • 自定义实体
<!-- 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;替换为其定义的值。最终的结果将是:

<example>
    Here is the custom entity: This is a custom entity
</example>

五. 实用场景示例

1. 动态表关联

<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

  • 动态关联用户资料表:

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

    <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:

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. 批量操作优化

<!-- 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> 标签:

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

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

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

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

整体效果

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

List<User> userList = new ArrayList<>();
userList.add(new User(1, "newUsername1"));
userList.add(new User(2, "newUsername2"));

生成的最终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 标签复用。


http://www.kler.cn/a/504296.html

相关文章:

  • SQL面试题1:连续登陆问题
  • Anaconda安装(2024最新版)
  • RuoYi-Vue-Plus 加入 GitCode:驱动多租户后台管理创新发展
  • Redis快速入门店铺营业状态设置
  • Python使用socket实现简易的http服务
  • 浅谈云计算06 | 云管理系统架构
  • idea无法下载源码
  • 逐“绿”前行 企业综合能源管控低碳转型如何推进?
  • Linux服务器网络丢包场景及解决办法
  • HDFS迁移distcp,源端数据新增,致迁移失败处理
  • python3GUI--大屏可视化-XX产业大数据指挥舱(附下载地址) By:PyQt5
  • LeetCode:39. 组合总和
  • FLASK创建下载
  • No.1|Godot|俄罗斯方块复刻|棋盘和初始方块的设置
  • 自动生成数据:SQLark 让数据测试更高效
  • 自定义封装进度条标签
  • 设计模式 行为型 责任链模式(Chain of Responsibility Pattern)与 常见技术框架应用 解析
  • JS后盾人--再一次的走进JS?
  • STM32程序发生异常崩溃时,怎样从串口输出当时的程序调用栈等信息
  • LangChain学习笔记2 Prompt 模板
  • 21_Spring Boot缓存注解介绍
  • 【Go】Go Gin框架初识(一)
  • 从零开始:在服务器上部署大模型并集成到 vscode +Cline使用
  • LLaMa-3 8B + 蒙特卡洛树 约等于 GPT-4
  • 常用的前端4种请求方式
  • 《拉依达的嵌入式\驱动面试宝典》—Linux篇(二)_uboot