瑞星 发表于 2025-1-15 16:55:05

[笔记] 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 全面优化
一. 基础标签

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 子句,会主动去除多余的 AND 或 OR。
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: 要遍历的集合或数组(list、array、map等)。
[*]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 <!]> #{minAge}
</select>
   处理特殊字符。
3. 特殊字符:XML 实体(关联 CDATA 区段)



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


[*]< 对应 <。
[*]> 对应 >。
[*]& 对应 &。
[*]" 对应 "。
[*]' 对应 &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 举行模块化处理
[*]保持代码整齐和可读性
七. 留意事项


[*]#{} 和 ${} 的区别:

[*]#{} 会举行预编译,防止 SQL 注入。
[*]${} 直接更换,有 SQL 注入风险。

[*]动态 SQL 的顺序很紧张,要留意逻辑的先后顺序。
[*]批量操作时留意数据库的性能限制。
[*]复杂查询建议使用 resultMap 而不是 resultType。
[*]对于大量重复的 SQL 片断,建议使用 sql 标签复用。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: [笔记] MyBatis-Plus XML 配置详解:从基础到高级,全面提升开辟服从