MyBatis中表和实体类的映射
MyBatis 表 ↔ 实体类映射
数据库表字段(下划线user_name),Java 实体属性(驼峰userName)。
两种方案:自动映射、手动 resultMap 映射。
表:
t_user| id | user_name | user_age | dept_id |
|----|-----------|----------|---------|
| 1 | 张三 | 22 | 1001 |
实体 User.java
public class User { private Long id; private String userName; private Integer userAge; private Long deptId; // getter setter }一、自动映射(resultType)
MyBatis 自动映射规则:列名和实体属性完全一样就自动赋值。
情况 1:数据库下划线,实体驼峰(最常见业务场景)
开启全局配置:下划线转驼峰,不需要写任何映射,直接用resultType。
yml 配置
mybatis: configuration: map-underscore-to-camel-case: true- 数据库列
user_name→ Java 属性userName - 数据库列
user_age→ Java 属性userAge
mapper xml
<select id="selectAll" resultType="com.entity.User"> select id,user_name,user_age,dept_id from t_user </select>✅ 查询结果自动封装 User 对象。
⚠️注意:这个配置只作用于
resultType,同样也对resultMap生效。
情况 2:字段名字完全一致(不推荐数据库这样设计)
数据库列userName,实体属性userName,不需要开启配置,直接自动映射。
自动映射失效场景
- 没有开启下划线转驼峰,数据库下划线,实体驼峰 → 属性为 null
- sql 查询的列名和实体属性名完全不匹配
- 多表关联查询、嵌套对象、一对一 / 一对多,自动映射搞不定,必须
resultMap
二、手动映射 resultMap(核心重点)
适用场景:
- 数据库列名和实体属性差异很大
- 一对一、一对多关联查询
- 需要指定主键、typeHandler 自定义类型处理
- 不想开启全局下划线转驼峰配置
基础语法
<!-- type:实体全类名 / 别名;id:resultMap唯一标识 --> <resultMap id="userResultMap" type="com.entity.User"> <!-- <id> 映射主键字段,提升MyBatis解析性能,主键一定要写 --> <id column="id" property="id"/> <!-- column:sql查询出来的列名;property:实体类属性名 --> <result column="user_name" property="userName"/> <result column="user_age" property="userAge"/> <result column="dept_id" property="deptId"/> </resultMap> <!-- 使用resultMap,不要写resultType --> <select id="selectUser" resultMap="userResultMap"> select id,user_name,user_age,dept_id from t_user where id=#{id} </select>关键点:
column是SQL 查询返回的列名,不是原始表字段名! 如果写了别名select user_name as uname,那 column 就要写uname。
别名示例
<select id="selectUser" resultMap="userResultMap"> select id,user_name as uname from t_user </select> <resultMap id="userResultMap" type="User"> <id column="id" property="id"/> <result column="uname" property="userName"/> </resultMap>三、一对一关联映射(association)
User 里面包含 Dept 对象
public class User { private Long id; private String userName; private Dept dept; // 一对一 } public class Dept { private Long deptId; private String deptName; }方式 1:联合查询,一次 SQL(业务常用)
<resultMap id="userDeptMap" type="User"> <id column="u_id" property="id"/> <result column="user_name" property="userName"/> <!-- association:一对一对象映射 property=实体属性名 javaType=对象类型 --> <association property="dept" javaType="Dept"> <id column="d_id" property="deptId"/> <result column="dept_name" property="deptName"/> </association> </resultMap> <select id="getUser" resultMap="userDeptMap"> select u.id u_id, u.user_name, d.id d_id, d.dept_name from t_user u left join t_dept d on u.dept_id = d.id where u.id=#{id} </select>方式 2:嵌套查询(多 SQL,会产生 N+1 问题)
<resultMap id="userDeptMap" type="User"> <id column="id" property="id"/> <result column="user_name" property="userName"/> <!-- select:调用另外一个mapper方法;column:传给子查询的参数 --> <association property="dept" javaType="Dept" select="com.mapper.DeptMapper.selectById" column="dept_id"/> </resultMap>注意 N+1 问题:查询 N 条用户,会额外发起 N 次查询部门,大数据量禁止。
四、一对多关联映射(collection)
一个用户多个订单,User 中存放 List<Order> orderList
public class User { private Long id; private String userName; private List<Order> orderList; //一对多 } public class Order{ private Long orderId; private String orderNo; }<resultMap id="userOrderMap" type="User"> <id column="u_id" property="id"/> <result column="user_name" property="userName"/> <!-- collection:集合映射,ofType集合里面元素类型 --> <collection property="orderList" ofType="Order"> <id column="o_id" property="orderId"/> <result column="order_no" property="orderNo"/> </collection> </resultMap> <select id="getUserOrder" resultMap="userOrderMap"> select u.id u_id, u.user_name, o.id o_id, o.order_no from t_user u left join t_order o on u.id = o.user_id where u.id=#{id} </select>ofType:集合泛型里面的实体类型,不是写 List。
五、resultMap 复用:extends 继承
<!--基础resultMap --> <resultMap id="baseUserMap" type="User"> <id column="id" property="id"/> <result column="user_name" property="userName"/> </resultMap> <!--继承上面,追加字段,不用重复写 --> <resultMap id="userWithDeptMap" extends="baseUserMap" type="User"> <association property="dept" javaType="Dept"> <id column="d_id" property="deptId"/> </association> </resultMap>六、常见坑
resultType和resultMap二选一,不能同时写column是查询出来的列名,不是表原始字段,注意 sql 别名- 下划线转驼峰只对 resultType 生效,resultMap 不受影响,resultMap 需要手动写 column-property
<association>用javaType;<collection>用ofType,不要搞混- 嵌套子查询容易 N+1,生产尽量用left join 单 sql
- 实体属性大小写严格区分,property 必须和实体 getter/setter 对应
- 主键尽量写
<id/>标签,MyBatis 内部缓存、去重依赖主键,不写会出现重复对象
自动映射 vs resultMap 选型
表格
| 方案 | 适用场景 |
|---|---|
| resultType + 下划线驼峰配置 | 单表简单查询,字段一一对应 |
| resultMap | 字段名差异、一对一、一对多、复杂关联查询 |
补充:MyBatis‑Plus 封装了实体注解
@TableName、@TableField,底层也是生成 mybatis 的映射逻辑。
