Master MyBatis resultMap: From Simple Queries to Complex Mappings
This article explains the powerful MyBatis resultMap element, covering basic getter/setter injection, constructor injection, inheritance, one-to-one and one-to-many associations, and discriminators, while providing complete XML examples and Java entity code to help developers map complex relational data efficiently.
1. Introduction
resultMap is the most important and powerful element in MyBatis. It frees you from writing repetitive JDBC ResultSet extraction code, allowing you to replace thousands of lines of code with a concise mapping definition. Simple statements require zero configuration, while more complex ones only need relationships described.
resultMapcan aggregate complex query results such as multi‑table joins, one‑to‑one or one‑to‑many relationships into a single result set. This article provides a detailed explanation of resultMap with a demo at the end.
2. resultMap
Next we look at how resultMap performs mapping.
2.1 Getter/Setter Injection
We declare an entity class that corresponds to the database:
@Data
public class Employee implements Serializable {
private static final long serialVersionUID = -7145891282327539285L;
private String employeeId;
private String employeeName;
private Integer employeeType;
}The corresponding resultMap is:
<mapper namespace="cn.felord.mybatis.mapper.EmployeeMapper">
<resultMap id="EmployeeMap" type="cn.felord.mybatis.entity.Employee">
<id column="employee_id" property="employeeId"/>
<result column="employee_name" property="employeeName"/>
<result column="employee_type" property="employeeType"/>
</resultMap>
</mapper>The attributes are explained as follows:
<mapper namespace="global unique namespace">
<resultMap id="unique within namespace" type="mapped entity class">
<id column="primary key column or alias, improves performance" property="entity field"/>
<result column="database column or alias" property="entity field"/>
</resultMap>
</mapper>Injection uses Getter and Setter methods, so the entity must have a no‑arg constructor and corresponding getters/setters.
2.2 Constructor Injection
MyBatis also supports constructor injection. If Employee has the following constructor:
public Employee(String employeeId, String employeeName, Integer employeeType) {
this.employeeId = employeeId;
this.employeeName = employeeName;
this.employeeType = employeeType;
}The resultMap can be written as:
<mapper namespace="cn.felord.mybatis.mapper.EmployeeMapper">
<resultMap id="EmployeeMap" type="cn.felord.mybatis.entity.Employee">
<constructor>
<idArg column="employee_id" javaType="String"/>
<arg column="employee_name" javaType="String"/>
<arg column="employee_type" javaType="String"/>
</constructor>
</resultMap>
</mapper>If the property attribute is omitted, MyBatis injects values according to the constructor parameter order. Since MyBatis 3.4.3, the name attribute allows arguments to be out of order:
<mapper namespace="cn.felord.mybatis.mapper.EmployeeMapper">
<resultMap id="EmployeeConstructorMap" type="cn.felord.mybatis.entity.Employee">
<constructor>
<idArg column="employee_id" javaType="String" name="employeeId"/>
<!-- you can add arguments in any order -->
<arg column="employee_type" javaType="Integer" name="employeeType"/>
<arg column="employee_name" javaType="String" name="employeeName"/>
</constructor>
</resultMap>
</mapper>2.3 Inheritance
Like Java classes, resultMap can inherit from another map. The diagram below shows two related Java classes:
The resultMap for RegularEmployee extends EmployeeMap:
<resultMap id="RegularEmployeeMap" extends="EmployeeMap" type="cn.felord.mybatis.entity.RegularEmployee">
<result column="level" property="level"/>
<result column="job_number" property="jobNumber"/>
<association property="department" javaType="cn.felord.mybatis.entity.Department">
<id column="department_id" property="departmentId"/>
<result column="department_name" property="departmentName"/>
<result column="department_level" property="departmentLevel"/>
</association>
</resultMap>2.4 One-to-One Association
The last resultMap in the inheritance example contains an association tag, which maps a RegularEmployee to a single Department object:
<resultMap id="RegularEmployeeMap" extends="EmployeeMap" type="cn.felord.mybatis.entity.RegularEmployee">
<result column="level" property="level"/>
<result column="job_number" property="jobNumber"/>
<association property="department" javaType="cn.felord.mybatis.entity.Department">
<id column="department_id" property="departmentId"/>
<result column="department_name" property="departmentName"/>
<result column="department_level" property="departmentLevel"/>
</association>
</resultMap>association can be nested further if the associated object also has one‑to‑one relationships.
2.5 One-to-Many Collection
For a department that has many employees we can map a list of employees into a DepartmentAndEmployeeList class:
public class DepartmentAndEmployeeList extends Department {
private static final long serialVersionUID = -2503893191396554581L;
private List<Employee> employees;
public List<Employee> getEmployees() { return employees; }
public void setEmployees(List<Employee> employees) { this.employees = employees; }
}The corresponding resultMap uses the collection element:
<resultMap id="DepartmentAndEmployeeListMap" extends="DepartmentMap" type="cn.felord.mybatis.entity.DepartmentAndEmployeeList">
<collection property="employees" ofType="cn.felord.mybatis.entity.RegularEmployee">
<id column="employee_id" property="employeeId"/>
<result column="employee_name" property="employeeName"/>
<result column="level" property="level"/>
<result column="job_number" property="jobNumber"/>
</collection>
</resultMap>2.6 Discriminator
When an employee can be either a regular or a temporary worker, a discriminator decides which subclass to instantiate, similar to a Java switch statement.
public class DepartmentAndTypeEmployees extends Department {
private static final long serialVersionUID = -2503893191396554581L;
private List<RegularEmployee> regularEmployees;
private List<TemporaryEmployee> temporaryEmployees;
// getters and setters
}The resultMap with discriminators looks like:
<resultMap id="DepartmentAndTypeEmployeesMap" extends="DepartmentMap" type="cn.felord.mybatis.entity.DepartmentAndTypeEmployees">
<collection property="regularEmployees" ofType="cn.felord.mybatis.entity.RegularEmployee">
<discriminator javaType="int" column="employee_type">
<case value="1">
<id column="employee_id" property="employeeId"/>
<result column="employee_name" property="employeeName"/>
<result column="employee_type" property="employeeType"/>
<result column="level" property="level"/>
<result column="job_number" property="jobNumber"/>
</case>
</discriminator>
</collection>
<collection property="temporaryEmployees" ofType="cn.felord.mybatis.entity.TemporaryEmployee">
<discriminator javaType="int" column="employee_type">
<case value="0">
<id column="employee_id" property="employeeId"/>
<result column="employee_name" property="employeeName"/>
<result column="employee_type" property="employeeType"/>
<result column="company_no" property="companyNo"/>
</case>
</discriminator>
</collection>
</resultMap>Note that the collection tags must be declared first, and the discriminator placed inside each collection.
3. Summary
resultMapsatisfies most data‑mapping scenarios in MyBatis. This article covered its basic and advanced usages, including inheritance, one‑to‑one, one‑to‑many, and discriminators. While powerful, excessive nesting can affect maintainability and performance, especially with large collections. Use it wisely and refer to the official MyBatis documentation for additional attributes.
For the demo code, follow the public account and reply with resultMap to receive it.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
