MyBatis-Flex實現(xiàn)多表聯(lián)查(自動映射)
簡介:
MyBatis-Flex 是一個優(yōu)雅的 MyBatis 增強框架,它非常輕量、同時擁有極高的性能與靈活性。我們可以輕松的使用 Mybaits-Flex 鏈接任何數(shù)據(jù)庫,其內(nèi)置的 "QueryWrapper " → 亮點,幫助我們極大的減少了 SQL 編寫的工作的同時,減少出錯的可能性。
官網(wǎng):
MyBatis-Flex - MyBatis-Flex 官方網(wǎng)站
多表聯(lián)查
初始對比:
為了方便熟悉,我們和mybatis-plus的查詢做一個對比,更加容易理解:
MyBatis-Flex:
QueryWrapper query = new QueryWrapper()
.select(
ACCOUNT.ID,
ACCOUNT.USER_NAME,
max(ACCOUNT.BIRTHDAY),
avg(ACCOUNT.SEX).as("sex_avg")
);
List<Employee> employees = employeeMapper.selectListByQuery(query);MyBatis-Plus:
QueryWrapper<Employee> queryWrapper = new QueryWrapper<>();
queryWrapper
.select(
"id"
,"user_name"
,"max(birthday)"
,"avg(birthday) as sex_avg"
);
List<Employee> employees = employeeMapper.selectList(queryWrapper);在多表聯(lián)查前面我們先嘗試一個基礎(chǔ)查詢(基礎(chǔ)映射):
@Table(value = "tb_account")
public class Account {
@Id(keyType = KeyType.Auto)
private Long id;
private String userName;
private int age;
//getter setter
}Account.java 與表 tb_account 是字段和屬性是一一對應關(guān)系的。此時,我們在查詢數(shù)據(jù)的時候,可以通過 AccountMapper 方法直接查詢,例如:
QueryWrapper qw = new QueryWrapper();
qw.select(ACCOUNT.ALL_COLUMNS)
.where(ACCOUNT.ID.ge(100));
List<Account> accounts = accountMapper.selectListByQuery(qw);或者使用如下的鏈式查詢,都可以直接得到 List<Account> 結(jié)果:accounts。
QueryChain.of(accountMapper)
.select(ACCOUNT.ALL_COLUMNS)
.where(ACCOUNT.ID.ge(100))
.list();AS 映射
假設我們在 Account.java 中多定義了一些其他屬性,如下所示:
@Table(value = "tb_account")
public class Account {
@Id(keyType = KeyType.Auto)
private Long id;
private String userName;
private int age;
//最大年齡
private int maxAge;
//平均年齡
private int avgAge;
//getter setter
}那么,我們在查詢的時候,就可以通過 as 進行映射關(guān)聯(lián),查詢代碼如下:
QueryChain.of(accountMapper)
.select(
ACCOUNT.ALL_COLUMNS,
max(ACCOUNT.AGE).as("maxAge"),
avg(ACCOUNT.AGE).as("avgAge")
).where(ACCOUNT.ID.ge(100))
.groupBy(ACCOUNT.AGE)
.list();或者:
QueryChain.of(accountMapper)
.select(
ACCOUNT.ALL_COLUMNS,
max(ACCOUNT.AGE).as("max_age"),
avg(ACCOUNT.AGE).as("avg_age")
).where(ACCOUNT.ID.ge(100))
.groupBy(ACCOUNT.AGE)
.list();或者使用 lambda:
QueryChain.of(accountMapper)
.select(
ACCOUNT.ALL_COLUMNS,
max(ACCOUNT.AGE).as(Account::getMaxAge),
avg(ACCOUNT.AGE).as(Account::getAvgAge)
).where(ACCOUNT.ID.ge(100))
.groupBy(Account::getAge)
.list();以上代碼執(zhí)行的 SQL 如下:
select tb_account.*
, max(tb_account.age) as maxAge
, avg(tb_account.age) as avgAge
where tb_account.id >= 100
group by tb_account.age多表映射
假設我們定義了一個 BootVo.java,其中包含了圖書的基本信息,也包含了圖書歸屬的用戶信息,例如:
public class BookVo {
//圖書的基本字段
private Long id;
private Long accountId;
private String title;
private String content;
//用戶表的字段
private String userName;
private int userAge;
}此時,我們再進行 left join 多表查詢時,代碼如下:
List<BookVo> bookVos = QueryChain.of(bookMapper)
.select(
BOOK.ALL_COLUMNS, //圖書的所有字段
ACCOUNT.USER_NAME, //用戶表的 user_name 字段
ACCOUNT.AGE.as("userAge") //用戶表的 age 字段, as "userAge"
).from(BOOK)
.leftJoin(ACCOUNT).on(BOOK.ACCOUNT_ID.eq(ACCOUNT.ID))
.where(ACCOUNT.ID.ge(100))
.listAs(BookVo.class);或者,我們也可以直接在 BookVo 中,定義 Account 對象,例如:
public class BookVo {
//圖書的基本字段
private Long id;
private Long accountId;
private String title;
private String content;
//用戶
private Account account;
}查詢代碼如下:
List<BookVo> bookVos = QueryChain.of(bookMapper)
.select(
BOOK.DEFAULT_COLUMNS,
ACCOUNT.DEFAULT_COLUMNS,
)
.from(BOOK)
.leftJoin(ACCOUNT).on(BOOK.ACCOUNT_ID.eq(ACCOUNT.ID))
.where(ACCOUNT.ID.ge(100))
.listAs(BookVo.class);高級映射?
在以上的表結(jié)構(gòu)中,一個賬戶可以有多本圖書,那么我們假設定義的 AccountVo.java 的結(jié)構(gòu)如下:
public class AccountVO {
private Long id;
private String userName;
private int age;
//賬戶擁有的 圖書列表
private List<Book> books;
}List<AccountVO> bookVos = QueryChain.of(accountMapper)
.select() // 不傳入?yún)?shù)等同于 SQL 的 select *
.from(ACCOUNT)
.leftJoin(BOOK).on(ACCOUNT.ID.eq(BOOK.ACCOUNT_ID))
.where(ACCOUNT.ID.ge(100))
.listAs(AccountVO.class);亦或者指定查詢參數(shù):
List<AccountVO> bookVos = QueryChain.of(accountMapper)
.select(
ACCOUNT.ID,
ACCOUNT.USER_NAME,
ACCOUNT.AGE,
BOOK.TITLE,
BOOK.CONTENT,
)
.from(ACCOUNT)
.leftJoin(BOOK).on(ACCOUNT.ID.eq(BOOK.ACCOUNT_ID))
.where(ACCOUNT.ID.ge(100))
.listAs(AccountVO.class);高級映射的場景中,我們還可以通過注解 @RelationManyToOne 進行查詢, 詳情請點擊 這里。
重名映射?
在很多類型嵌套的場景下,可能會出現(xiàn)字段名定義重復的情況,例如:
@TableRef(Account.class)
public class AccountVO {
private Long id;
private String name;
private int age;
//賬戶擁有的 圖書列表
private List<Book> book;
}public class Book {
private Long id;
private Long accountId;
private String name;
}在以上的嵌套定義中, AccountVO 以及 Book 都包含了 id 和 name 的定義,假設我們查詢的方法如下:
List<AccountVO> bookVos = QueryChain.of(accountMapper)
.select(
ACCOUNT.ID,
ACCOUNT.NAME,
ACCOUNT.AGE,
BOOK.ID,
BOOK.NAME,
)
.from(ACCOUNT)
.leftJoin(BOOK).on(ACCOUNT.ID.eq(BOOK.ACCOUNT_ID))
.where(ACCOUNT.ID.ge(100))
.listAs(AccountVO.class);其執(zhí)行的 SQL 如下:
select tb_account.id as tb_account$id,
tb_account.name as tb_account$name,
tb_account.age,
tb_book.id as tb_book$id, -- Flex 發(fā)現(xiàn)有重名時,會自動添加上 as 別名
tb_book.name as tb_book$name -- Flex 發(fā)現(xiàn)有重名時,會自動添加上 as 別名
from tb_account
left join tb_book on tb_account.id = tb_book.account_id
where tb_account.id >= 100此時,查詢的數(shù)據(jù)可以正常映射到 AccountVO 類。
注意事項
- 在查詢 VO 類當中有重名字段時,需要給 VO 類標記
@TableRef注解,指定其對應的實體類,以正確添加別名。 - 在 QueryWrapper 的
select(...)中,MyBatis-Flex 在 多表查詢 的情況下,且有相同的字段名時,MyBatis-Flex 內(nèi)部會主動幫助用戶添加上 as 別名,默認為:表名$字段名。
錯誤的情況:
若我們修改查詢代碼如下:
List<AccountVO> bookVos = QueryChain.of(accountMapper)
.select()
.from(ACCOUNT)
.leftJoin(BOOK).on(ACCOUNT.ID.eq(BOOK.ACCOUNT_ID))
.where(ACCOUNT.ID.ge(100))
.listAs(AccountVO.class);那么,其執(zhí)行的 SQL 如下:
select * from tb_account left join tb_book on tb_account.id = tb_book.account_id where tb_account.id >= 100
此時,查詢的結(jié)果集中,會有多個 id 和 name 列,程序無法知道 id 和 name 對應的應該是 AccountVO 的還是 Book 的,因此,可能會出現(xiàn)數(shù)據(jù)錯誤賦值的情況。
所以,若程序中出現(xiàn)包裹對象有重名屬性的情況時,QueryWrapper 的 select(...) 方法必須傳入具體的字段才能保證數(shù)據(jù)正常賦值。
如下的代碼也是沒問題的:
List<AccountVO> bookVos = QueryChain.of(accountMapper)
.select(
ACCOUNT.DEFAULT_COLUMNS,
BOOK.DEFAULT_COLUMNS
)
.from(ACCOUNT)
.leftJoin(BOOK).on(ACCOUNT.ID.eq(BOOK.ACCOUNT_ID))
.where(ACCOUNT.ID.ge(100))
.listAs(AccountVO.class);@ColumnAlias 注解:
@ColumnAlias 注解的作用是用于定義在 entity 查詢時,默認的 SQL 別名名稱,可以取代自動生成的別名,例如:
public class Book {
@ColumnAlias("bookId")
private Long id;
private Long accountId;
@ColumnAlias("bookName")
private String name;
}那么,假設我們的查詢代碼如下:
List<AccountVO> bookVos = QueryChain.of(accountMapper)
.select(
ACCOUNT.ID,
ACCOUNT.NAME,
ACCOUNT.AGE,
BOOK.ID,
BOOK.NAME,
)
.from(ACCOUNT)
.leftJoin(BOOK).on(ACCOUNT.ID.eq(BOOK.ACCOUNT_ID))
.where(ACCOUNT.ID.ge(100))
.listAs(AccountVO.class);其執(zhí)行的 SQL 為:
select tb_account.id, tb_account.name, tb_account.age,
tb_book.id as bookId, -- @ColumnAlias("bookId")
tb_book.name as bookName -- @ColumnAlias("bookName")
from tb_account
left join tb_book on tb_account.id = tb_book.account_id
where tb_account.id >= 100此時,數(shù)據(jù)也是可以正常映射。
到此這篇關(guān)于MyBatis-Flex實現(xiàn)多表聯(lián)查(自動映射)的文章就介紹到這了,更多相關(guān)MyBatis-Flex多表聯(lián)查內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MyBatis-Flex實現(xiàn)分頁查詢的示例代碼
- Mybatis-flex整合達夢數(shù)據(jù)庫的實現(xiàn)示例
- Spring Boot整合MyBatis-Flex全過程
- SpringBoot使用MyBatis-Flex實現(xiàn)靈活的數(shù)據(jù)庫訪問
- mybatis-flex實現(xiàn)鏈式操作的示例代碼
- mybatis-flex實現(xiàn)多數(shù)據(jù)源操作
- Springboot集成Mybatis-Flex的示例詳解
- mybatis-flex與springBoot整合的實現(xiàn)示例
- MyBatis-Flex 邏輯刪除的用法小結(jié)
相關(guān)文章
關(guān)于@Autowierd && @Resource 你真的了解嗎
這篇文章主要介紹了關(guān)于@Autowierd && @Resource的具體使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08
SpringBoot集成SpringSecurity安全框架方式
這篇文章主要介紹了SpringBoot集成SpringSecurity安全框架方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05
java實現(xiàn)簡易超市管理系統(tǒng) 附源碼下載
這篇文章主要介紹了java實現(xiàn)簡易超市管理系統(tǒng)(含源碼),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03
Spring Boot如何優(yōu)雅的使用多線程實例詳解
這篇文章主要給大家介紹了關(guān)于Spring Boot如何優(yōu)雅的使用多線程的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Spring Boot具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2020-05-05

