Difference Between ResultType and ResultMap
In MyBatis development, the <select> tag is the workhorse of data retrieval. However, the real magic happens in how the raw database rows are transformed into meaningful Java objects. This transformation is governed by two fundamental attributes: resultType and resultMap.
While they both serve the same ultimate goal—mapping SQL results to Java types—they operate on entirely different philosophies. Understanding when to use a "quick and easy" approach versus a "precise and powerful" one is essential for writing maintainable and efficient persistence layers.resultType is the most straightforward way to handle query results. It relies on MyBatis's ability to automatically match database column names to Java object properties. This is often referred to as "convention over configuration."
How it Works
When you specify a resultType, MyBatis looks at the column names returned by your SQL query and attempts to find matching field names in the target Java class. If the names match exactly, the mapping happens seamlessly.
<select id="getUserById" resultType="com.example.entity.User">
SELECT id, username, password, email FROM user WHERE id = #{id}
</select>
Handling Name Mismatches
In many real-world scenarios, database naming conventions (like snake_case) differ from Java naming conventions (camelCase). There are two primary ways to bridge this gap when using resultType:
SQL Aliases: You can use the
ASkeyword in your SQL statement to rename columns on the fly so they match your Java properties.<select id="getUserById" resultType="com.example.entity.User"> SELECT id, user_name AS username, password FROM user WHERE id = #{id} </select>Global Configuration: If your project consistently uses underscores in the database and camelCase in Java, you can enable the automatic camel-case mapping in your MyBatis configuration. This eliminates the need for manual aliases.
mybatis: configuration: map-underscore-to-camel-case: true
The Limitations of resultType
While efficient, resultType is not a silver bullet. It has clear boundaries:
- Simple Mappings Only: It can only handle one-to-one mappings where one column corresponds to one property.
- No Structural Complexity: It cannot handle nested objects or collections.
- Rigid Logic: If the mapping logic becomes too complex for simple aliases or camel-case settings,
resultTypebecomes insufficient.
Mastering resultMap: The Custom Powerhouse
When the relationship between your database schema and your domain model becomes complex, resultMap is your go-to solution. Unlike resultType, which is automatic, resultMap requires you to explicitly define how each column maps to each property.
Basic Usage and Performance
A resultMap allows you to define specific rules for every field. It is highly recommended to use the <id> tag for primary keys, as this helps MyBatis optimize its internal caching and identity management.
<resultMap id="userResultMap" type="com.example.entity.User">
<id property="id" column="id"/>
<result property="username" column="user_name"/>
<result property="password" column="password"/>
</resultMap>
<select id="getUserById" resultMap="userResultMap">
SELECT id, user_name, password FROM user WHERE id = #{id}
</select>
Handling Complex Relationships
The true strength of resultMap lies in its ability to handle object graphs through nested mappings.
1. One-to-One Associations (<association>)
If a User object contains an Address object, you can use the <association> tag to map the columns of a joined table into a nested Java object.
<resultMap id="orderResultMap" type="com.example.entity.Order">
<id property="id" column="order_id"/>
<result property="orderNo" column="order_no"/>
<association property="user" javaType="com.example.entity.User">
<id property="id" column="user_id"/>
<result property="username" column="user_name"/>
</association>
</resultMap>
2. One-to-Many Collections (<collection>)
When a single record (like a User) is associated with multiple records (like a list of Orders), the <collection> tag allows you to encapsulate these multiple rows into a Java List or Set.
<resultMap id="userWithOrdersMap" type="com.example.entity.User">
<id property="id" column="id"/>
<result property="username" column="user_name"/>
<collection property="orders" ofType="com.example.entity.Order">
<id property="id" column="order_id"/>
<result property="orderNo" column="order_no"/>
</collection>
</resultMap>
Key Differences at a Glance
To help you decide quickly during development, here is a comparison of the two:
| Feature | resultType |
resultMap |
|---|---|---|
| Mapping Logic | Automatic (based on name matching) | Explicit (manually defined) |
| Configuration Effort | Low (minimal setup) | Moderate to High (requires definition) |
| Relationship Support | None (flat mapping only) | Full (supports <association> and <collection>) |
| Handling Mismatches | Requires SQL aliases or global config | Handled directly within the mapping |
| Flexibility | Low | High (fine-grained control) |
Important Note: In any single <select> statement, you must choose either resultType or resultMap. You cannot use both simultaneously.
Decision Framework: Which One Should You Use?
Choosing the right tool depends on the complexity of your query and your data structure. Follow these professional guidelines:
Use
resultTypeif:- The database column names match your Java property names.
- You have enabled
map-underscore-to-camel-case. - You are performing simple, single-table queries that return a flat structure.
- You want to keep your XML files concise and readable.
Use
resultMapif:- You are performing joins that result in nested objects (One-to-One).
- You are retrieving a parent object with a list of child objects (One-to-Many).
- The column names and property names are significantly different and you don't want to clutter your SQL with aliases.
- You need fine-grained control over how specific data types are handled.
Team Consistency:
In large-scale enterprise projects, some teams prefer to useresultMapexclusively. While this requires more initial configuration, it provides a unified way to manage all mappings and makes the persistence layer highly predictable.
Summary
resultType is built for speed and simplicity, making it ideal for routine, flat queries. resultMap is built for power and precision, making it indispensable for complex domain models and relational data. A skilled developer knows how to balance these two, leveraging the simplicity of resultType where possible and the robustness of resultMap where necessary.