MyBatis-Flex多表關(guān)聯(lián)查詢指南分享
MyBatis-Flex 提供了強大且靈活的多表關(guān)聯(lián)查詢支持,其核心是通過 QueryWrapper 和 Relations 注解來實現(xiàn)的。與 MyBatis-Plus 等框架的關(guān)聯(lián)查詢不同,MyBatis-Flex 的關(guān)聯(lián)查詢是在不涉及 JOIN 的 SQL 的情況下,通過多次查詢來實現(xiàn)的,這種方式在某些場景下(如分頁、大數(shù)據(jù)量)反而有更好的性能表現(xiàn)。
MyBatis-Flex 的多表關(guān)聯(lián)主要分為兩種類型:
- 基于
QueryWrapper的關(guān)聯(lián)查詢(動態(tài)、手動) - 基于
@Relation注解的關(guān)聯(lián)查詢(靜態(tài)、自動)
1. 基于QueryWrapper的關(guān)聯(lián)查詢 (Manual)
這種方式非常靈活,你可以通過 QueryWrapper 動態(tài)地指定關(guān)聯(lián)關(guān)系和查詢條件。它主要通過 select(...) 和 leftJoin/innerJoin 等方法來實現(xiàn),但其底層機制依然是分開查詢再組合。
核心語法示例:
假設(shè)我們有 Account(賬戶)表和 Book(書籍)表,一個賬戶對應(yīng)多本書。
// 1. 查詢賬戶及其書籍(1對多)
QueryWrapper query = QueryWrapper.create()
.select() // 查詢主表(Account)的所有字段
.from(Account.class)
// 使用 leftJoin 或 innerJoin 定義關(guān)聯(lián)關(guān)系(注意:這只是定義關(guān)系,不生成SQL JOIN)
.leftJoin(Book.class).on(Account::getId).eq(Book::getAccountId))
// 添加查詢條件
.where(Account::getUserName).like("張三")
.and(Book::getPublishDate).ge(LocalDate.now().minusYears(1));
// 執(zhí)行查詢
// 注意:這里返回的仍然是 List<Account>,但MyBatis-Flex會通過額外查詢自動填充其Book列表
List<Account> accounts = accountMapper.selectListByQuery(query);
關(guān)鍵點:
leftJoin(Book.class)和on(...)方法定義了Account和Book之間的關(guān)聯(lián)關(guān)系。
MyBatis-Flex 看到這個定義后,會執(zhí)行以下步驟:
- 首先查詢滿足條件的
Account列表。 - 然后根據(jù)
on條件中定義的關(guān)聯(lián)關(guān)系(Account.id = Book.account_id),再發(fā)起一次查詢,獲取所有相關(guān)的Book。 - 最后,自動將
Book列表設(shè)置到對應(yīng)Account對象的books屬性中(需要你有這個屬性)。
2. 基于@Relation注解的關(guān)聯(lián)查詢 (Auto)
這種方式是聲明式的。你需要在實體類的字段上使用 @Relation 注解來定義關(guān)聯(lián)關(guān)系,之后在查詢時,MyBatis-Flex 會自動幫你完成數(shù)據(jù)的填充。這是最常用和推薦的方式。
@Relation 注解支持多種關(guān)聯(lián)類型:
| 關(guān)聯(lián)類型 | 注解值 | 說明 |
|---|---|---|
| 一對一 | RelationType.OneToOne | 例如:一個員工對應(yīng)一個工位 |
| 多對一 | RelationType.ManyToOne | 例如:多本書屬于同一個作者 |
| 一對多 | RelationType.OneToMany | 例如:一個作者擁有多本書 |
| 多對多 | RelationType.ManyToMany | 例如:一個學生選修多門課程,一門課程有多個學生 |
語法與示例
a. 一對多 (OneToMany)
在 Account 實體類中,定義一個 List<Book> 字段,并加上注解。
public class Account {
private Long id;
private String userName;
// 關(guān)鍵:使用 @Relation 注解定義一對多關(guān)系
@Relation(
value = RelationType.OneToMany, // 關(guān)聯(lián)類型
targetField = "accountId" // 目標表(Book)中的關(guān)聯(lián)字段
)
private List<Book> books;
// ... getters and setters
}
public class Book {
private Long id;
private String title;
private Long accountId; // 這個字段與 Account.id 關(guān)聯(lián)
// ... getters and setters
}
查詢時,直接使用普通查詢即可,關(guān)聯(lián)數(shù)據(jù)會自動填充:
// 無需在 QueryWrapper 中寫 join,直接查
QueryWrapper query = QueryWrapper.create()
.where(Account::getUserName).eq("張三");
List<Account> accounts = accountMapper.selectListByQuery(query);
// 此時,每個 accounts 中的 Account 對象,其 books 屬性已被自動填充
b. 多對一 (ManyToOne)
在 Book 實體類中,定義一個 Account 字段。
public class Book {
private Long id;
private String title;
private Long accountId;
// 關(guān)鍵:使用 @Relation 注解定義多對一關(guān)系
@Relation(
value = RelationType.ManyToOne, // 關(guān)聯(lián)類型
targetField = "accountId", // 當前表(Book)中的關(guān)聯(lián)字段
// 指定目標表的關(guān)聯(lián)字段,默認為 id,可省略
targetFieldBind = "id"
)
private Account account;
// ... getters and setters
}
查詢書籍時,作者信息會自動填充:
List<Book> books = bookMapper.selectAll(); // 每個 Book 對象的 account 屬性已被自動填充
c. 多對多 (ManyToMany)
多對多需要一個中間表。例如 Student, Course, StudentCourse。
public class Student {
private Long id;
private String name;
@Relation(
value = RelationType.ManyToMany,
// 中間表實體類
targetTable = "tb_student_course",
// 當前對象在中間表中的字段
selfField = "id",
// 當前對象在中間表中的字段(selfField)對應(yīng)的中間表字段
selfTargetField = "student_id",
// 目標對象在中間表中的字段(targetField)對應(yīng)的中間表字段
targetTargetField = "course_id",
// 目標表實體類
targetTableField = "tb_course",
// 目標對象的關(guān)聯(lián)字段(通常是id)
targetField = "id"
)
private List<Course> courses;
}
3. 關(guān)聯(lián)查詢與條件
無論是哪種方式,你都可以輕松地添加關(guān)聯(lián)表的查詢條件。
使用 QueryWrapper 添加關(guān)聯(lián)表條件:
QueryWrapper query = QueryWrapper.create()
.select()
.from(Account.class)
// 定義關(guān)聯(lián)關(guān)系
.leftJoin(Book.class).on(Account::getId).eq(Book::getAccountId))
// 主表條件
.where(Account::getUserName).like("張")
// 關(guān)聯(lián)表條件?。。?
.and(Book::getPrice).gt(new BigDecimal("50.00"))
.and(Book::getStatus).eq(1);
List<Account> accounts = accountMapper.selectListByQuery(query);
使用 @Relation 時,通過 extraCondition 添加額外條件:
public class Account {
@Relation(
value = RelationType.OneToMany,
targetField = "accountId",
// 額外條件:只查詢狀態(tài)為已發(fā)布的書籍
extraCondition = "status = 1 and price > 50"
)
private List<Book> publishedExpensiveBooks;
}
總結(jié)對比
| 特性 | 基于 QueryWrapper | 基于 @Relation 注解 |
|---|---|---|
| 靈活性 | 高,可動態(tài)構(gòu)建復(fù)雜關(guān)聯(lián) | 中,關(guān)系在代碼中預(yù)先定義 |
| 便捷性 | 低,每次查詢需手動編寫關(guān)聯(lián) | 高,定義一次,隨處使用 |
| 代碼侵入性 | 無,不修改實體類 | 有,需要在實體類中添加注解和字段 |
| 適用場景 | 動態(tài)、復(fù)雜的關(guān)聯(lián)查詢 | 固定的、常見的關(guān)聯(lián)關(guān)系 |
最佳實踐建議:
- 對于業(yè)務(wù)中固定的關(guān)聯(lián)關(guān)系(如查詢用戶時總要顯示他的訂單),使用
@Relation注解。 - 對于動態(tài)的、一次性的復(fù)雜關(guān)聯(lián)查詢(如根據(jù)多個動態(tài)條件關(guān)聯(lián)查詢),使用
QueryWrapper手動關(guān)聯(lián)。 - 靈活處理復(fù)雜關(guān)聯(lián)使用基于QueryWrapper的關(guān)聯(lián)查詢 (Manual),配置即可實現(xiàn)關(guān)聯(lián)查詢使用基于 @Relation注解的關(guān)聯(lián)查詢 (Auto)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
利用Log4j將不同Package的日志輸出到不同文件的方法
日志是應(yīng)用軟件中不可缺少的部分,Apache的開源項目log4j是一個功能強大的日志組件,提供方便的日志記錄。這篇文章主要介紹了利用Log4j將不同Package的日志輸出到不同文件的方法,需要的朋友可以參考借鑒,下面來跟著小編一起學習學習吧。2017-01-01
GSON框架下將百度天氣JSON數(shù)據(jù)轉(zhuǎn)JavaBean
這篇文章主要為大家詳細介紹了如何在GSON框架下實現(xiàn)將百度天氣JSON數(shù)據(jù)轉(zhuǎn)JavaBean,文中的示例代碼講解詳細,感興趣的小伙伴可以了解下2025-08-08
SpringMvc靜態(tài)資源訪問實現(xiàn)方法代碼實例
這篇文章主要介紹了SpringMvc靜態(tài)資源訪問實現(xiàn)方法代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-08-08
SpringBoot定制三種錯誤頁面及錯誤數(shù)據(jù)方法示例
Spring Boot提供的默認異常處理機制通常并不一定適合我們實際的業(yè)務(wù)場景,因此,我們通常會根據(jù)自身的需要對Spring Boot全局異常進行統(tǒng)一定制,例如定制錯誤頁面,定制錯誤數(shù)據(jù)等。本文主要介紹了SpringBoot三種自定義錯誤頁面的實現(xiàn),快來學習吧2021-12-12
spring boot異步(Async)任務(wù)調(diào)度實現(xiàn)方法
在沒有使用spring boot之前,我們的做法是在配置文件中定義一個任務(wù)池,然后將@Async注解的任務(wù)丟到任務(wù)池中去執(zhí)行,那么在spring boot中,怎么來實現(xiàn)異步任務(wù)的調(diào)用了,下面通過本文給大家講解,需要的朋友參考下2018-02-02
Spring中allowedOriginPatterns和allowedOrigins方法有何不同詳解
這篇文章主要給大家介紹了關(guān)于Spring中allowedOriginPatterns和allowedOrigins方法有何不同,allowedOriginPatterns和allowedOrigins都是用來設(shè)置允許跨域請求的來源,需要的朋友可以參考下2023-10-10

