核心概念

  1. ResultMap
    MyBatis 的核心映射配置,用于定义数据库字段与 Java 对象属性的对应关系。
  2. MyBatis-Plus 默认映射
    默认开启驼峰转下划线(如 userNameuser_name),字段名一致时无需配置。
  3. 自定义场景
    字段名不一致、嵌套对象(一对一/一对多)、类型转换等复杂映射需自定义 ResultMap。

操作步骤(XML 方式)

1. 创建实体类
@Data
public class User {
    private Long id;
    private String name;      // 数据库字段:real_name
    private Integer age;      // 数据库字段:user_age
    private String email;
    
    // 嵌套对象(部门)
    private Department dept;  // 数据库字段需联表查询
}
2. 定义 ResultMap

UserMapper.xml 中配置:

<resultMap id="UserResultMap" type="User">
    <!-- 主键映射 -->
    <id column="id" property="id"/>
    
    <!-- 字段名不一致的映射 -->
    <result column="real_name" property="name"/>
    <result column="user_age" property="age"/>
    
    <!-- 普通字段 -->
    <result column="email" property="email"/>
    
    <!-- 嵌套对象映射(一对一) -->
    <association property="dept" javaType="Department">
        <id column="dept_id" property="id"/>
        <result column="dept_name" property="name"/>
    </association>
</resultMap>
3. Mapper 接口引用 ResultMap
public interface UserMapper extends BaseMapper<User> {
    // 引用自定义 ResultMap
    @Select("SELECT u.*, d.id AS dept_id, d.name AS dept_name " +
            "FROM user u LEFT JOIN department d ON u.dept_id = d.id " +
            "WHERE u.id = #{id}")
    @ResultMap("UserResultMap") // 指定 ResultMap ID
    User selectUserWithDept(Long id);
}
4. 配置 XML 路径(确保文件被扫描)
# application.yml
mybatis-plus:
  mapper-locations: classpath*:/mapper/**/*.xml

注解方式实现

@Select("SELECT * FROM user WHERE id = #{id}")
@Results(id = "userMap", value = {
    @Result(column = "real_name", property = "name"),
    @Result(column = "user_age", property = "age"),
    @Result(property = "dept", column = "dept_id",
            one = @One(select = "com.example.mapper.DepartmentMapper.selectById"))
})
User selectByIdCustom(Long id);

常见错误与解决方案

  1. 字段映射失败(值为 null)

    • ✅ 检查字段名拼写(区分大小写)
    • ✅ 确认 ResultMap 中 column 与 SQL 查询列名一致
    • ✅ 关闭自动驼峰映射(冲突时):
      mybatis-plus:
        configuration:
          map-underscore-to-camel-case: false
      
  2. ResultMap 未生效

    • ✅ 检查 XML 路径配置是否正确
    • ✅ 确认 Mapper 方法引用了正确的 @ResultMap("id")
    • ✅ 清理缓存(如开启)并重启项目
  3. 嵌套查询 N+1 问题

    • ✅ 使用 JOIN 一次性查询(推荐)
    • ✅ 懒加载:@One(fetchType = FetchType.LAZY)

注意事项

  1. 优先级规则
    @ResultMap > XML ResultMap > 自动驼峰映射 > 字段名严格匹配。

  2. 关联查询性能
    避免多层嵌套 select 语句(导致多次查询),优先使用 JOIN + 单 ResultMap。

  3. ID 唯一性
    ResultMap 的 id 需全局唯一,建议命名规范:类名ResultMap(如 UserResultMap)。


使用技巧

  1. 复用 ResultMap

    <!-- 定义基础映射 -->
    <resultMap id="BaseUserMap" type="User" autoMapping="true">
        <id column="id" property="id"/>
    </resultMap>
    
    <!-- 扩展嵌套映射 -->
    <resultMap id="UserWithDeptMap" extends="BaseUserMap" type="User">
        <association property="dept" resultMap="DeptResultMap"/>
    </resultMap>
    
  2. 自动映射匹配
    开启自动映射未配置字段(需确保字段名能匹配):

    <resultMap id="UserMap" type="User" autoMapping="true">
        <id column="id" property="id"/>
        <!-- 显式配置特殊字段 -->
        <result column="real_name" property="name"/>
    </resultMap>
    
  3. 类型处理器
    自定义字段类型转换(如枚举、JSON):

    <result column="tags" property="tags" 
            typeHandler="com.example.handler.JsonTypeHandler"/>
    

最佳实践与性能优化

  1. 精简查询字段
    SELECT * → 明确指定所需字段,减少数据传输量。

  2. 避免过度嵌套
    超过 3 层的嵌套对象建议拆分为多次查询(通过 Service 层组装)。

  3. 启用懒加载
    对非必要嵌套对象使用懒加载:

    mybatis-plus:
      configuration:
        lazy-loading-enabled: true
        aggressive-lazy-loading: false # 按需加载
    
  4. 二级缓存慎用
    高频更新数据避免缓存,只读数据可开启:

    <cache eviction="LRU" flushInterval="60000"/>
    

示例:完整 XML 配置

<!-- UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
    <resultMap id="UserResultMap" type="User" autoMapping="false">
        <id column="id" property="id"/>
        <result column="real_name" property="name"/>
        <result column="user_age" property="age"/>
        <result column="email" property="email"/>
        
        <association property="dept" javaType="Department">
            <id column="dept_id" property="id"/>
            <result column="dept_name" property="name"/>
        </association>
    </resultMap>

    <select id="selectUserWithDept" resultMap="UserResultMap">
        SELECT 
            u.id, u.real_name, u.user_age, u.email,
            d.id AS dept_id, d.name AS dept_name
        FROM user u
        LEFT JOIN department d ON u.dept_id = d.id
        WHERE u.id = #{id}
    </select>
</mapper>

关键总结

  • 简单场景:依赖默认映射 + @TableField 注解。
  • 复杂映射:XML ResultMap + 显式配置字段/嵌套对象。
  • 性能核心:减少查询次数、避免 SELECT *、合理使用懒加载。