如何将查询结果映射到 Java 对象? MyBatis 支持哪些结果映射方式? 它们有什么区别?

将查询结果映射到 Java 对象是 MyBatis 的核心功能之一,它使得我们可以方便地将数据库中的数据转换为 Java 对象,进行后续的处理和操作。

MyBatis 支持的主要结果映射方式:

  1. 自动映射 (Auto-Mapping):

    • 原理: MyBatis 会根据查询结果集的列名(或列别名)与 Java 对象的属性名进行自动匹配,并将对应的值设置到 Java 对象的属性中。
    • 配置:
      • 全局配置:mybatis-config.xml 中,可以通过 <settings> 标签的 autoMappingBehavior 属性配置自动映射的行为:
        • NONE: 禁用自动映射。
        • PARTIAL: 只映射结果集中存在的列,如果结果集中缺少某个属性对应的列,则该属性保持默认值(null 或基本类型的默认值)。
        • FULL: 映射结果集中存在的所有列,如果结果集中缺少某个属性对应的列,则抛出异常。
      • 局部配置:<resultMap> 中,可以通过 autoMapping 属性覆盖全局配置。
    • 驼峰命名转换: 如果开启了 mapUnderscoreToCamelCase 设置(默认为 false),MyBatis 会自动将数据库列名中的下划线(_)转换为 Java 属性名中的驼峰命名。例如,user_name 会自动映射到 userName 属性。
    • 适用场景: 简单的查询,数据库列名与 Java 对象属性名基本一致(或可以通过驼峰命名转换对应)。
    <!-- 全局配置 (mybatis-config.xml) -->
    <settings>
      <setting name="autoMappingBehavior" value="PARTIAL"/>
      <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    
    <!-- SQL 映射文件 (UserMapper.xml) -->
    <select id="selectUserById" parameterType="int" resultType="com.example.model.User">
      SELECT id, user_name, password, email FROM users WHERE id = #{id}
    </select>
    
  2. 使用 resultType 进行简单映射:

    • 原理: 与自动映射类似,MyBatis 会根据查询结果集的列名(或列别名)与 Java 对象的属性名进行自动匹配。
    • 配置:<select> 标签中使用 resultType 属性指定查询结果的 Java 类型。
    • 适用场景: 简单的查询,数据库列名与 Java 对象属性名基本一致(或可以通过驼峰命名转换对应)。
    <select id="selectUserById" parameterType="int" resultType="com.example.model.User">
      SELECT id, user_name, password, email FROM users WHERE id = #{id}
    </select>
    
  3. 使用 <resultMap> 进行自定义映射:

    • 原理: 通过 <resultMap> 标签定义一个自定义的结果映射规则,可以显式地指定每个数据库列与 Java 对象属性之间的映射关系。
    • 配置:
      • <resultMap> 标签:
        • id: resultMap 的唯一标识符。
        • type: 映射的 Java 类型。
      • <id> 标签:映射主键列。
        • property: Java 对象的属性名。
        • column: 数据库列名(或列别名)。
        • javaType: Java 类型(可选,MyBatis 可以自动推断)。
        • jdbcType: JDBC 类型(可选,MyBatis 可以自动推断)。
        • typeHandler: 类型处理器(可选)。
      • <result> 标签:映射普通列。 属性与<id>基本一致。
      • <association> 标签:映射一对一关联关系。
      • <collection> 标签:映射一对多关联关系。
      • <discriminator> 标签:鉴别器,根据某个列的值来决定使用哪个 resultMap 进行映射。
    • 适用场景:
      • 数据库列名与 Java 对象属性名不一致。
      • 需要使用类型处理器进行特殊的类型转换。
      • 复杂的关联查询(一对一、一对多、多对多)。
      • 需要根据不同的条件使用不同的映射规则(鉴别器)。
    <resultMap id="userResultMap" type="com.example.model.User">
      <id property="id" column="user_id"/>
      <result property="username" column="user_name"/>
      <result property="password" column="user_password"/>
      <result property="email" column="user_email" typeHandler="com.example.EmailTypeHandler"/>
    </resultMap>
    
    <select id="selectUserById" parameterType="int" resultMap="userResultMap">
      SELECT id AS user_id, user_name, password AS user_password, email FROM users WHERE id = #{id}
    </select>
    
  4. 关联映射 (Association and Collection):

    • <association> (一对一): 用于映射一对一关联关系。例如,一个用户(User)对应一个地址(Address)。

      <resultMap id="userWithAddressMap" type="User">
        <id property="id" column="user_id"/>
        <result property="username" column="username"/>
        <association property="address" javaType="Address">
          <id property="id" column="address_id"/>
          <result property="street" column="street"/>
          <result property="city" column="city"/>
        </association>
      </resultMap>
      
    • <collection> (一对多): 用于映射一对多关联关系。例如,一个用户(User)对应多个订单(Order)。

      <resultMap id="userWithOrdersMap" type="User">
        <id property="id" column="user_id"/>
        <result property="username" column="username"/>
        <collection property="orders" ofType="Order">
          <id property="id" column="order_id"/>
          <result property="orderDate" column="order_date"/>
        </collection>
      </resultMap>
      
    • 嵌套查询 (Nested Select) vs 嵌套结果 (Nested Results):

      • 嵌套查询:<association><collection> 中使用 select 属性指定另一个 SQL 语句来查询关联对象。 MyBatis 会执行额外的 SQL 查询。
      • 嵌套结果:<association><collection> 中使用 <resultMap> 定义嵌套的结果映射规则,MyBatis 会在一次 SQL 查询中获取所有数据,并在内存中进行映射。
      • 选择:
        • 嵌套查询:更灵活,可以减少一次性加载的数据量,但会增加数据库访问次数(N+1 查询问题)。
        • 嵌套结果:性能更高(只需要一次 SQL 查询),但需要一次性加载所有数据,可能导致内存消耗过大。
  5. 鉴别器 (Discriminator):

    • 原理: 根据某个列的值来决定使用哪个 resultMap 进行映射。
    • 适用场景: 当一个查询结果可以映射为多种不同的 Java 对象时,可以使用鉴别器来根据不同的条件选择不同的映射规则。 例如,根据 user_type 列的值来决定将查询结果映射为 AdminUser 对象还是 NormalUser 对象。
    <resultMap id="userDiscriminatorMap" type="User">
      <id property="id" column="user_id"/>
      <result property="username" column="username"/>
      <discriminator javaType="string" column="user_type">
        <case value="admin" resultMap="adminUserMap"/>
        <case value="normal" resultMap="normalUserMap"/>
      </discriminator>
    </resultMap>
    
    <resultMap id="adminUserMap" type="AdminUser" extends="userDiscriminatorMap">
      <result property="role" column="role"/>
    </resultMap>
    
    <resultMap id="normalUserMap" type="NormalUser" extends="userDiscriminatorMap">
      <result property="level" column="level"/>
    </resultMap>
    

区别总结:

映射方式原理配置适用场景
自动映射根据列名(或别名)与属性名自动匹配全局配置 (autoMappingBehavior) 或局部配置 (autoMapping)简单的查询,列名与属性名基本一致(或可通过驼峰命名转换对应)
resultType与自动映射类似,根据列名(或别名)与属性名自动匹配<select> 标签的 resultType 属性简单的查询,列名与属性名基本一致(或可通过驼峰命名转换对应)
<resultMap>显式指定每个列与属性的映射关系<resultMap> 标签,以及 <id>, <result>, <association>, <collection>, <discriminator>列名与属性名不一致、需要类型处理器、复杂的关联查询、需要鉴别器
关联映射使用 <association> (一对一) 或 <collection> (一对多) 映射关联对象<association><collection> 标签,以及 select (嵌套查询) 或 <resultMap> (嵌套结果)一对一、一对多关联查询
鉴别器根据某个列的值选择不同的 resultMap<discriminator> 标签,以及 <case> 标签一个查询结果可以映射为多种不同的 Java 对象

选择建议:

  • 对于简单的查询,优先使用自动映射或 resultType,代码更简洁。
  • 对于复杂的查询或需要自定义映射规则的场景,使用 <resultMap>
  • 对于关联查询,根据实际情况选择嵌套查询或嵌套结果。
  • 当一个查询结果可以映射为多种不同的 Java 对象时,使用鉴别器。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值