将查询结果映射到 Java 对象是 MyBatis 的核心功能之一,它使得我们可以方便地将数据库中的数据转换为 Java 对象,进行后续的处理和操作。
MyBatis 支持的主要结果映射方式:
-
自动映射 (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> -
使用
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> -
使用
<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> - 原理: 通过
-
关联映射 (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 查询),但需要一次性加载所有数据,可能导致内存消耗过大。
- 嵌套查询: 在
-
-
鉴别器 (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 对象时,使用鉴别器。


被折叠的 条评论
为什么被折叠?



