MyBatis 數(shù)據(jù)封裝全攻略(告別空值與映射混亂問題)
MyBatis 數(shù)據(jù)封裝全攻略:告別空值與映射混亂
在日常開發(fā)中,使用 MyBatis 進行數(shù)據(jù)庫操作時,你是否經(jīng)常遇到以下問題?
- 查詢結(jié)果部分字段為
null,導(dǎo)致前端顯示異常? - 多表聯(lián)查時對象嵌套關(guān)系映射失?。?/li>
- 字段名和屬性名不一致,結(jié)果集無法正確賦值?
- 集合類型(如 List)屬性始終為空?
- 使用
resultType返回 Map 時結(jié)構(gòu)混亂、不易維護?

這些問題本質(zhì)上都是 數(shù)據(jù)封裝(Result Mapping) 的問題。本文將系統(tǒng)性地為你梳理 MyBatis 中數(shù)據(jù)封裝的核心機制,并提供最佳實踐方案,助你徹底解決封裝難題!
一、MyBatis 數(shù)據(jù)封裝的兩種方式
1. resultType —— 簡單粗暴
適用于字段名與 Java 屬性名完全匹配的情況。
<select id="getUserById" resultType="com.example.User">
SELECT id, username, email FROM user WHERE id = #{id}
</select>? 優(yōu)點:簡潔、易用
? 缺點:無法處理駝峰命名、多表關(guān)聯(lián)、嵌套對象等復(fù)雜場景
?? 注意:若數(shù)據(jù)庫字段是
user_name,而 Java 屬性是userName,則不會自動映射!
二、開啟駝峰命名轉(zhuǎn)換(推薦基礎(chǔ)配置)
在 mybatis-config.xml 或 Spring Boot 配置中開啟:
# application.yml (Spring Boot)
mybatis:
configuration:
map-underscore-to-camel-case: true或 XML 配置:
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>開啟后,user_name → userName,create_time → createTime 自動映射。
三、resultMap —— 精準控制映射關(guān)系
當 resultType 無法滿足需求時,必須使用 <resultMap>。
基礎(chǔ)字段映射
<resultMap id="UserResultMap" type="com.example.User">
<id property="id" column="user_id"/> <!-- 主鍵建議用 id 標簽 -->
<result property="username" column="user_name"/>
<result property="email" column="email_addr"/>
<result property="createTime" column="gmt_create"/>
</resultMap>
<select id="getUserById" resultMap="UserResultMap">
SELECT user_id, user_name, email_addr, gmt_create
FROM user_info
WHERE user_id = #{id}
</select>??
id標簽用于主鍵,有助于性能優(yōu)化(緩存、嵌套查詢?nèi)ブ兀?/p>
四、處理對象嵌套 —— association
當 User 包含一個 Profile 對象:
public class User {
private Long id;
private String username;
private Profile profile; // 嵌套對象
}
public class Profile {
private String avatar;
private String bio;
}XML 映射:
<resultMap id="UserWithProfileResultMap" type="User">
<id property="id" column="user_id"/>
<result property="username" column="username"/>
<!-- 嵌套對象映射 -->
<association property="profile" javaType="Profile">
<result property="avatar" column="avatar_url"/>
<result property="bio" column="user_bio"/>
</association>
</resultMap>
<select id="getUserWithProfile" resultMap="UserWithProfileResultMap">
SELECT u.id as user_id, u.username,
p.avatar as avatar_url, p.bio as user_bio
FROM user u
LEFT JOIN profile p ON u.id = p.user_id
WHERE u.id = #{id}
</select>五、處理集合嵌套 —— collection
當 User 包含多個 Role:
public class User {
private Long id;
private String username;
private List<Role> roles; // 集合
}
public class Role {
private Long id;
private String roleName;
}XML 映射:
<resultMap id="UserWithRolesResultMap" type="User">
<id property="id" column="user_id"/>
<result property="username" column="username"/>
<!-- 集合映射 -->
<collection property="roles" ofType="Role">
<id property="id" column="role_id"/>
<result property="roleName" column="role_name"/>
</collection>
</resultMap>
<select id="getUserWithRoles" resultMap="UserWithRolesResultMap">
SELECT u.id as user_id, u.username,
r.id as role_id, r.name as role_name
FROM user u
LEFT JOIN user_role ur ON u.id = ur.user_id
LEFT JOIN role r ON ur.role_id = r.id
WHERE u.id = #{id}
</select>?? 注意:使用
ofType指定集合元素類型,而不是javaType
六、避免 N+1 查詢問題
上面的寫法雖然能正確封裝,但可能引發(fā) N+1 查詢。推薦使用 JOIN 查詢 + 分組封裝 或 分步查詢(懶加載)
方案一:分步查詢(推薦用于懶加載)
<resultMap id="UserLazyLoadResultMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<collection property="roles"
select="selectRolesByUserId"
column="id"
fetchType="lazy"/>
</resultMap>
<select id="selectUserById" resultMap="UserLazyLoadResultMap">
SELECT id, username FROM user WHERE id = #{id}
</select>
<select id="selectRolesByUserId" resultType="Role">
SELECT id, name as roleName FROM role
WHERE id IN (SELECT role_id FROM user_role WHERE user_id = #{userId})
</select>在配置中開啟懶加載:
mybatis:
configuration:
lazy-loading-enabled: true
aggressive-lazy-loading: false七、使用注解簡化映射(可選)
對于簡單場景,也可使用注解:
@Results(id = "UserResult", value = {
@Result(property = "id", column = "user_id"),
@Result(property = "username", column = "user_name"),
@Result(property = "profile", column = "user_id",
one = @One(select = "selectProfileByUserId"))
})
@Select("SELECT user_id, user_name FROM user WHERE id = #{id}")
User getUserById(Long id);八、實戰(zhàn)技巧 & 避坑指南
? 技巧 1:統(tǒng)一別名規(guī)范
在 SQL 中使用 AS 給字段起別名,避免列名沖突:
SELECT u.id AS user_id, r.id AS role_id, ...
? 技巧 2:復(fù)用 ResultMap
使用 <extend> 繼承已有的 ResultMap:
<resultMap id="BaseUserMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
</resultMap>
<resultMap id="UserWithProfileMap" extends="BaseUserMap">
<association property="profile" ... />
</resultMap>? 技巧 3:自動映射策略
<resultMap autoMapping="true" ...>
開啟后,未明確指定的匹配字段也會自動映射(需配合駝峰轉(zhuǎn)換)。
? 避坑 1:不要混用 resultType 和 resultMap
在一個 select 標簽內(nèi)只能使用其一。
? 避坑 2:集合屬性未初始化
確保 Java 實體中的 List 屬性已初始化:
private List<Role> roles = new ArrayList<>(); // 避免 null
九、終極解決方案:MyBatis-Plus(可選進階)
如果你覺得原生 MyBatis 配置繁瑣,可以考慮 MyBatis-Plus:
- 無需 XML,注解/條件構(gòu)造器即可完成復(fù)雜查詢
- 內(nèi)置 ResultMap 自動構(gòu)建
- 支持連表查詢插件(如
@TableField(select = false)+QueryWrapper聯(lián)查) - 分頁、樂觀鎖、代碼生成器一應(yīng)俱全
示例:
// MP 自動處理字段映射 + 駝峰
List<User> users = userMapper.selectList(
Wrappers.<User>lambdaQuery()
.eq(User::getUsername, "admin")
);總結(jié)
| 問題類型 | 解決方案 |
|---|---|
| 字段名不匹配 | 開啟駝峰 / 使用 <result> |
| 對象嵌套 | <association> |
| 集合嵌套 | <collection> |
| 性能優(yōu)化 | 分步查詢 + 懶加載 |
| 復(fù)雜聯(lián)查 | ResultMap + SQL 別名 |
| 快速開發(fā) | MyBatis-Plus |
掌握以上方法,你將能從容應(yīng)對 MyBatis 中 99% 的數(shù)據(jù)封裝問題!記得收藏本文,下次遇到映射失敗時,按圖索驥,輕松解決!
到此這篇關(guān)于MyBatis 數(shù)據(jù)封裝全攻略(告別空值與映射混亂問題)的文章就介紹到這了,更多相關(guān)MyBatis 數(shù)據(jù)封裝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot事務(wù)鉤子函數(shù)的使用方式
本文介紹了SpringBoot中事務(wù)鉤子函數(shù)的使用方式,包括常見場景、使用方式等,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-11-11
Java中使用數(shù)組實現(xiàn)棧數(shù)據(jù)結(jié)構(gòu)實例
這篇文章主要介紹了Java中使用數(shù)組實現(xiàn)棧數(shù)據(jù)結(jié)構(gòu)實例,本文先是講解了實現(xiàn)棧至少應(yīng)該包括以下幾個方法等知識,然后給出代碼實例,需要的朋友可以參考下2015-01-01

