MyBatis 的查询结果映射(Result Mapping)功能,像是一个桥梁,连接了数据库中的结果集和 Java 中的对象。通过它,SQL 查询返回的表数据被自动转换为我们熟悉的 Java 对象。这一过程的背后,依靠的是 反射机制 和 映射规则。接下来,我们一起来看看它的工作原理以及如何实现各种映射。
# 一、自动映射的简单逻辑
自动映射就像 “机智的助理”,它会尝试让数据库的列名和 Java 对象的字段名一一匹配。
- 这是一种较为通用且灵活的方式,可以随意命名。
- 但是开发中如果遵循一些规则的话,开发起来会更舒服,比如后面会提到的小驼峰命名和下划线映射,这就需要程序员遵循好命名规范了。
如何匹配? MyBatis 利用反射找到对象的字段名,然后逐一检查数据库的列名。如果两者一致(或者通过别名 AS 一致),MyBatis 会自动将列的值赋给字段。例如:
SELECT user_id AS id, user_name AS name FROM users; |
public class User { | |
private int id; | |
private String name; | |
// Getters and setters... | |
} |
user_id匹配id(通过别名),user_name匹配name,值自动填充。
代码示例:
@Select("SELECT id, name FROM user WHERE id = #{id}") | |
User selectUserById(int id); |
自动映射的好处是省时省力,但如果列名和字段名不一致时,就需要更灵活的手动映射。
# 二、手动映射 —— 显式定义规则
当 “助理” 搞不定时,你需要用 resultMap 手动告诉 MyBatis 如何映射。
使用场景:列名和字段名差别很大,比如列名是 user_id ,字段名却是 uid 。
** 如何操作?** 手动定义映射关系,让每一列清晰对应到 Java 对象字段。
示例代码:
<resultMap id="userResultMap" type="com.example.User">
<id column="user_id" property="id"/>
<result column="user_name" property="name"/>
</resultMap>
<select id="selectUserById" resultMap="userResultMap">
SELECT user_id, user_name FROM user WHERE user_id = #{id}
</select>
工作流程:
- 执行 SQL,获得
ResultSet。 - 按
resultMap的规则逐列映射。 - 使用反射给 Java 对象字段赋值。
# 三、注解映射的灵活使用
如果你喜欢代码清晰明了,可以用注解来定义映射规则。比如:
@Results({ | |
@Result(property = "id", column = "user_id", id = true), | |
@Result(property = "name", column = "user_name") | |
}) | |
@Select("SELECT user_id, user_name FROM user WHERE user_id = #{id}") | |
User selectUserById(int id); |
这里的 @Result 注解实现了类似 resultMap 的功能,让代码更紧凑。
# 四、高级映射 —— 嵌套对象和集合
如果查询结果不仅是简单字段,还包含嵌套对象或集合,MyBatis 也能处理。
-
嵌套对象: 当结果中包含复杂结构时,可以用
<association>指定嵌套对象的映射。<resultMap id="orderResultMap" type="com.example.Order"> <id column="order_id" property="id"/> <result column="order_date" property="date"/> <association property="user" javaType="com.example.User"> <id column="user_id" property="id"/> <result column="user_name" property="name"/> </association> </resultMap> <select id="selectOrderById" resultMap="orderResultMap"> SELECT o.order_id, o.order_date, u.user_id, u.user_name FROM orders o JOIN users u ON o.user_id = u.user_id WHERE o.order_id = #{id} </select>查询结果中的用户信息被映射到
Order对象中的User字段。 -
集合映射: 如果查询返回一个对象包含子对象集合,可以用
<collection>定义集合的映射规则。<resultMap id="departmentResultMap" type="com.example.Department"> <id column="dept_id" property="id"/> <result column="dept_name" property="name"/> <collection property="employees" ofType="com.example.Employee"> <id column="emp_id" property="id"/> <result column="emp_name" property="name"/> </collection> </resultMap> <select id="selectDepartmentWithEmployees" resultMap="departmentResultMap"> SELECT d.dept_id, d.dept_name, e.emp_id, e.emp_name FROM department d JOIN employee e ON d.dept_id = e.dept_id </select>
# 五、数据类型的自动转换
MyBatis 会根据数据库的列类型和 Java 字段类型自动完成数据转换。例如:
基本数据类型和包装类:
VARCHAR→StringINT→Integer或intBIGINT→Long或longDECIMAL→BigDecimalDATE→java.sql.Date或java.util.DateTIME→java.sql.TimeTIMESTAMP→java.sql.Timestamp
# 六、小驼峰与下划线的自动映射
MyBatis 提供自动映射功能,可以将数据库中的下划线命名( snake_case )的列名映射为 Java 类中小驼峰命名( camelCase )的字段名。
# 如何启用自动映射
在 MyBatis 配置文件中开启 mapUnderscoreToCamelCase 设置即可:
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
# 自动映射规则
- 数据库列名中的下划线会被移除,并将其后一个字母转为大写。
- 例如:
user_id→userIdcreated_at→createdAt
【示例】
数据库查询:
SELECT user_id, created_at FROM users; |
Java 类:
public class User { | |
private Integer userId; | |
private Date createdAt; | |
} |
SQL 查询结果会自动映射到 Java 对象中,无需额外配置。
【注意事项】
- 字段名不符合下划线或小驼峰规则时,可能需要手动映射。
- 启用后可能略微增加运行时解析开销,字段较多时建议优化配置。
# 七、查询结果映射的核心流程总结
- 解析结果集:MyBatis 执行 SQL,获得
ResultSet。 - 根据映射规则处理:通过自动映射、
resultMap或注解匹配列名和字段名。 - 对象实例化:利用反射创建对象。
- 赋值:调用字段的
set方法,将列的值赋值到字段。 - 复杂对象处理:递归映射嵌套对象或填充集合。
# 总结
MyBatis 的查询结果映射灵活性很高,既能满足简单场景,也能应对复杂的数据结构需求。理解其映射原理和机制,可以帮助我们更高效地完成数据库和 Java 对象之间的转换。
