MyBatis实战解析(一):动态SQL及结果映射(XML)

目录

一、前言

二、结果集映射

1.自动映射

2.复杂结果集映射

3. 子映射嵌套子查询

4.结果集映射注意事项 

1.父子映射字段不要重复

2.子映射字段必须要有映射(如果需要这个字段的值)

3.结果集映射继承

三、动态SQL

四、结语


一、前言

MyBatis作为一款轻量级的持久层框架,凭借其灵活的SQL编写能力和强大的结果映射机制,成为Java开发中数据库操作的重要工具。动态SQL和结果映射是MyBatis的核心特性,能够显著提升开发效率并简化复杂业务场景下的数据库交互。

本系列文章将深入剖析MyBatis的实战应用,从动态SQL的编写技巧到结果映射的高级用法,结合实际案例帮助开发者掌握MyBatis的核心功能。通过解析常见场景和最佳实践,为高效、优雅的数据库操作提供实用指导。

二、结果集映射

MyBatis的结果集映射是将数据库查询结果转换为Java对象的核心机制,尤其适用于字段名和属性名不一致、嵌套对象、关联表等复杂场景。主要通过XML配置或注解实现。以下是常见映射方式与技巧:

1.自动映射

如果字段名和java类的属性名大部分一致,可以开启自动映射

    <resultMap id="BaseResultMap" type="org.wal.userdemo.entity.UserEntity">
        <id column="id" property="id" />
        <!-- name 、age 、birthday此处可省略映射 -->
        <result column="name" property="name" />
        <result column="age" property="age" />
        <result column="birthday" property="birthday" />
        <result column="create_time" property="createTime" />
        <result column="update_time" property="updateTime" />
        <result column="create_by" property="createBy" />
        <result column="update_by" property="updateBy" />
        <result column="del_flag" property="delFlag" />
    </resultMap>

    <select id="getAllUsers" resultMap="BaseResultMap" parameterType="org.wal.userdemo.DTO.req.UserDTOReq">
        select * from user
    </select>

2.复杂结果集映射

新建QualificationEntity实体类

/**
* 学历表
* @TableName qualification
*/
@Data
public class QualificationEntity {

    /**
    * 主键
    */
    private Integer id;
    /**
    * user表主键
    */
    private Integer userId;
    /**
    * 毕业院校
    */
    private String school;
    /**
    * 入学时间
    */
    private Date enterData;
    /**
    * 毕业时间
    */
    private Date graduateData;
    /**
    * 专业
    */
    private String magor;

}

在UserEntity添加属性 学历QualificationEntity

@Data
public class UserEntity extends BaseEntity{

    /**
     * id 主键
     */
    private Integer id;
    /**
     * name 姓名
     */
    private String name;
    /**
     * age 年龄
     */
    private Integer age;
    /**
     * birthday 生日
     */
    private Date birthday;
    /**
     * Qualification 学历
     */
    private List<QualificationEntity> qualList;

}

在xml中添加映射子结果集

    <resultMap id="BaseResultMap" type="org.wal.userdemo.entity.UserEntity">
        <id column="id" property="id" />
        <!-- name 、age 、birthday此处可省略映射 -->
        <result column="name" property="name" />
        <result column="age" property="age" />
        <result column="birthday" property="birthday" />
        <result column="create_time" property="createTime" />
        <result column="update_time" property="updateTime" />
        <result column="create_by" property="createBy" />
        <result column="update_by" property="updateBy" />
        <result column="del_flag" property="delFlag" />
        <!-- 映射用户所对应的学历信息 -->
        <collection property="qualList" ofType="org.wal.userdemo.entity.QualificationEntity">
            <result column="user_id" property="userId"/>
            <result column="school" property="school"/>
            <result column="enter_data" property="enterData"/>
            <result column="graduate_data" property="graduateData"/>
            <result column="magor" property="magor"/>
        </collection>
    </resultMap>

    <select id="getAllUsers" resultMap="BaseResultMap" parameterType="org.wal.userdemo.DTO.req.UserDTOReq">
        select u.*,
               q.*
        from user u
                 left join qualification q on u.id = q.user_id
        where u.name = '张'
          and u.del_flag = 0;
    </select>

启动项目,用postman模拟http请求

3.子映射嵌套子查询

在映射结果中可定义子查询sql。

用postman测试结果如下:

优点:

   1.sql简单,子查询sql可多处调用。

   2.可开启懒加载,按需使用。

注:什么是mybatis的懒加载?

代码解释示例如下:

UserEntity user = userMapper.getAllUsers();
List<QualificationEntity> qualList = user.getQualList();  // 此时才触发子查询

注:懒加载需要再yml文件中添加如下配置:

  configuration:   
    lazy-loading-enabled: true  #启用延迟加载
    aggressive-lazy-loading: false #是否在访问任意属性时触发延迟加载(建议关闭)

4.结果集映射注意事项 

1.父子映射字段不要重复

子映射结果集(qualification表)映射字段不要跟主映射结果集(user表)有重复映射字段,如下:

这样会影响映射结果集映射,postman测试如下: 

可以发现子结果的id和主结果的id值一样,并且只有一个子结果(也可能出现异常或其他问题)

解决方案一: 重复id定义前缀,sql中具体字段对应上别名,如下:

2.子映射字段必须要有映射(如果需要这个字段的值)

子映射结果字段必须要映射,因为子映射结果是默认不支持自动映射的,如下:

不能像主映射(user表)那样java类和数据库字段一样就省略,不然会造成如下结果(省略了school就映射不到school):

解决方案一:子结果集映射补全需要的字段(过程略)。

解决方案二:配置mybatis全自动映射 :如下,在yml文件中添加配置

注: mybatis的映射配置分三种:无自动映射、部分自动映射(默认)、全自动映射,区别如下

需要的同学可自行配置。 

3.结果集映射继承

mybatis的映射结果集是支持继承的,如下:

三、动态SQL

1.<where>

 用于构建动态查询条件,自动去除开头的 AND 或 OR。

<select id="getAllUsers" resultMap="BaseResultMap" parameterType="org.wal.userdemo.DTO.req.UserDTOReq">
        select * from user
        <where>
            <if test="name != null">and name like concat('%',#{name},'%')</if>
            <if test="age != null">and age &lt;= #{age}</if>
            <if test="birthday != null">and birthday = #{birthday}</if>
        </where>;
    </select>

2.<if>

条件判断语句,根据参数是否存在添加相应的 SQL 片段。

    <select id="getAllUsers" resultMap="BaseResultMap" parameterType="org.wal.userdemo.DTO.req.UserDTOReq">
        select * from user
        <where>
            <if test="name != null">and name like concat('%',#{name},'%')</if>
            <if test="age != null">and age &lt;= #{age}</if>
            <if test="birthday != null">and birthday = #{birthday}</if>
        </where>;
    </select>

 3.<choose>、<when>、<otherwise>

类似于 Java 的 switch-case语法,选择一个匹配的条件。

   <select id="getAllUsers" resultMap="BaseResultMap" parameterType="org.wal.userdemo.DTO.req.UserDTOReq">
        select * from user
        <where>
            <choose>
                <when test="name != null">
                    and name like concat('%',#{name},'%')
                </when>
                <when test="age != null">
                    and age &lt; #{age}
                </when>
                <otherwise> <!-- 不满足上面的where,则默认 -->
                    and del_flag = 0
                </otherwise>
            </choose>
        </where>
        ;

4.<set>

用于更新操作,自动去除末尾的逗号。

  <update id="updateUser" parameterType="org.wal.userdemo.entity.UserEntity">
        update
        <set>
            <if test="name != null">name = #{name},</if>
            <if test="age != null">age = #{age}</if>
        </set>
        where id = #{id};
    </update>

 5.<trim>

可以在 SQL 语句前后添加或移除特定的字符串(如 AND, OR, WHERE, SET 等)。

<select id="getUsersByPage" resultMap="BaseResultMap" parameterType="String">
       select *
       from user
       <trim prefix="LIMIT " suffixOverrides=",">
           #{pageNum}, #{pageSize}
       </trim>;
   </select>

6.<foreach>

遍历集合,常用于 IN 子句或批量插入/更新。 

   <select id="getUsersByIds" resultMap="BaseResultMap" parameterType="list">
       select * from user
       <where>
           id in
           <foreach collection="ids" item="id" open="(" separator="," close=")">
               #{id}
           </foreach>
       </where>;
   </select>

7.<bind>

创建一个变量并绑定到上下文,可以在 SQL 中使用。

 <select id="searchUsers" resultMap="BaseResultMap">
       <bind name="pattern" value="'%' + name + '%'" />
       select * from user where name like #{pattern};
   </select>

 8.<include> 和 <sql>

定义可重用的 SQL 片段。

  <sql id="userColumns">id, name, age, birthday, create_time, update_time, create_by, update_by, del_flag</sql>

   <select id="getAllUsers" resultMap="BaseResultMap">
       select <include refid="userColumns"/> from user;
   </select>

9.示例整合

 可以根据需要自行选择标签

<select id="complexQuery" resultMap="BaseResultMap" parameterType="org.wal.userdemo.DTO.req.UserDTOReq">
    select <include refid="userColumns"/>
    from user
    <where>
        <choose>
            <when test="name != null">
                <bind name="pattern" value="'%' + name + '%'" />
                name like #{pattern}
            </when>
            <when test="age != null">
                age &lt; #{age}
            </when>
            <otherwise>
                del_flag = 0
            </otherwise>
        </choose>
        <if test="ids != null and ids.size() > 0">
            and id in
            <foreach collection="ids" item="id" open="(" separator="," close=")">
                #{id}
            </foreach>
        </if>
    </where>
    <trim prefix="ORDER BY " suffixOverrides=",">
        id DESC
    </trim>;
</select>

四、结语

MyBatis的动态SQL和结果映射功能为复杂数据库操作提供了强大支持。通过合理运用自动映射、嵌套查询和懒加载等特性,可以显著提升开发效率和代码可维护性。动态SQL的灵活条件组合让查询逻辑更清晰,而结果映射机制则简化了对象关系转换的过程。掌握这些核心技巧,能够应对各种业务场景下的数据持久化需求。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值