MyBatis-Flex實(shí)現(xiàn)多表聯(lián)查(自動(dòng)映射)
簡(jiǎn)介:
MyBatis-Flex 是一個(gè)優(yōu)雅的 MyBatis 增強(qiáng)框架,它非常輕量、同時(shí)擁有極高的性能與靈活性。我們可以輕松的使用 Mybaits-Flex 鏈接任何數(shù)據(jù)庫(kù),其內(nèi)置的 "QueryWrapper " → 亮點(diǎn),幫助我們極大的減少了 SQL 編寫的工作的同時(shí),減少出錯(cuò)的可能性。
官網(wǎng):
MyBatis-Flex - MyBatis-Flex 官方網(wǎng)站
多表聯(lián)查
初始對(duì)比:
為了方便熟悉,我們和mybatis-plus的查詢做一個(gè)對(duì)比,更加容易理解:
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)查前面我們先嘗試一個(gè)基礎(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
是字段和屬性是一一對(duì)應(yīng)關(guān)系的。此時(shí),我們?cè)诓樵償?shù)據(jù)的時(shí)候,可以通過(guò) AccountMapper
方法直接查詢,例如:
QueryWrapper qw = new QueryWrapper(); qw.select(ACCOUNT.ALL_COLUMNS) .where(ACCOUNT.ID.ge(100)); List<Account> accounts = accountMapper.selectListByQuery(qw);
或者使用如下的鏈?zhǔn)讲樵儯伎梢灾苯拥玫?nbsp;List<Account>
結(jié)果:accounts
。
QueryChain.of(accountMapper) .select(ACCOUNT.ALL_COLUMNS) .where(ACCOUNT.ID.ge(100)) .list();
AS 映射
假設(shè)我們?cè)?nbsp;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 }
那么,我們?cè)诓樵兊臅r(shí)候,就可以通過(guò) as
進(jìn)行映射關(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
多表映射
假設(shè)我們定義了一個(gè) BootVo.java
,其中包含了圖書(shū)的基本信息,也包含了圖書(shū)歸屬的用戶信息,例如:
public class BookVo { //圖書(shū)的基本字段 private Long id; private Long accountId; private String title; private String content; //用戶表的字段 private String userName; private int userAge; }
此時(shí),我們?cè)龠M(jìn)行 left join
多表查詢時(shí),代碼如下:
List<BookVo> bookVos = QueryChain.of(bookMapper) .select( BOOK.ALL_COLUMNS, //圖書(shū)的所有字段 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
對(duì)象,例如:
public class BookVo { //圖書(shū)的基本字段 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);
高級(jí)映射?
在以上的表結(jié)構(gòu)中,一個(gè)賬戶可以有多本圖書(shū),那么我們假設(shè)定義的 AccountVo.java
的結(jié)構(gòu)如下:
public class AccountVO { private Long id; private String userName; private int age; //賬戶擁有的 圖書(shū)列表 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);
高級(jí)映射的場(chǎng)景中,我們還可以通過(guò)注解 @RelationManyToOne
進(jìn)行查詢, 詳情請(qǐng)點(diǎn)擊 這里。
重名映射?
在很多類型嵌套的場(chǎng)景下,可能會(huì)出現(xiàn)字段名定義重復(fù)的情況,例如:
@TableRef(Account.class) public class AccountVO { private Long id; private String name; private int age; //賬戶擁有的 圖書(shū)列表 private List<Book> book; }
public class Book { private Long id; private Long accountId; private String name; }
在以上的嵌套定義中, AccountVO
以及 Book
都包含了 id
和 name
的定義,假設(shè)我們查詢的方法如下:
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)有重名時(shí),會(huì)自動(dòng)添加上 as 別名 tb_book.name as tb_book$name -- Flex 發(fā)現(xiàn)有重名時(shí),會(huì)自動(dòng)添加上 as 別名 from tb_account left join tb_book on tb_account.id = tb_book.account_id where tb_account.id >= 100
此時(shí),查詢的數(shù)據(jù)可以正常映射到 AccountVO
類。
注意事項(xiàng)
- 在查詢 VO 類當(dāng)中有重名字段時(shí),需要給 VO 類標(biāo)記
@TableRef
注解,指定其對(duì)應(yīng)的實(shí)體類,以正確添加別名。 - 在 QueryWrapper 的
select(...)
中,MyBatis-Flex 在 多表查詢 的情況下,且有相同的字段名時(shí),MyBatis-Flex 內(nèi)部會(huì)主動(dòng)幫助用戶添加上 as 別名,默認(rèn)為:表名$字段名
。
錯(cuò)誤的情況:
若我們修改查詢代碼如下:
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
此時(shí),查詢的結(jié)果集中,會(huì)有多個(gè) id
和 name
列,程序無(wú)法知道 id
和 name
對(duì)應(yīng)的應(yīng)該是 AccountVO
的還是 Book
的,因此,可能會(huì)出現(xiàn)數(shù)據(jù)錯(cuò)誤賦值的情況。
所以,若程序中出現(xiàn)包裹對(duì)象有重名屬性的情況時(shí),QueryWrapper
的 select(...)
方法必須傳入具體的字段才能保證數(shù)據(jù)正常賦值。
如下的代碼也是沒(méi)問(wèn)題的:
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 查詢時(shí),默認(rèn)的 SQL 別名名稱,可以取代自動(dòng)生成的別名,例如:
public class Book { @ColumnAlias("bookId") private Long id; private Long accountId; @ColumnAlias("bookName") private String name; }
那么,假設(shè)我們的查詢代碼如下:
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í),數(shù)據(jù)也是可以正常映射。
到此這篇關(guān)于MyBatis-Flex實(shí)現(xiàn)多表聯(lián)查(自動(dòng)映射)的文章就介紹到這了,更多相關(guān)MyBatis-Flex多表聯(lián)查內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MyBatis-Flex實(shí)現(xiàn)分頁(yè)查詢的示例代碼
- Mybatis-flex整合達(dá)夢(mèng)數(shù)據(jù)庫(kù)的實(shí)現(xiàn)示例
- Spring Boot整合MyBatis-Flex全過(guò)程
- SpringBoot使用MyBatis-Flex實(shí)現(xiàn)靈活的數(shù)據(jù)庫(kù)訪問(wèn)
- mybatis-flex實(shí)現(xiàn)鏈?zhǔn)讲僮鞯氖纠a
- mybatis-flex實(shí)現(xiàn)多數(shù)據(jù)源操作
- Springboot集成Mybatis-Flex的示例詳解
- mybatis-flex與springBoot整合的實(shí)現(xiàn)示例
- MyBatis-Flex 邏輯刪除的用法小結(jié)
相關(guān)文章
關(guān)于@Autowierd && @Resource 你真的了解嗎
這篇文章主要介紹了關(guān)于@Autowierd && @Resource的具體使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08如何在MyBatis中實(shí)現(xiàn)DataSource
今天給大家整理了如何在MyBatis中實(shí)現(xiàn)DataSource,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下2021-06-06SpringBoot集成SpringSecurity安全框架方式
這篇文章主要介紹了SpringBoot集成SpringSecurity安全框架方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05jfinal添加jcaptcha驗(yàn)證碼實(shí)現(xiàn)方法
這篇文章主要介紹了jfinal的jcaptcha驗(yàn)證碼實(shí)現(xiàn)方法,大家參考使用吧2014-01-01java實(shí)現(xiàn)簡(jiǎn)易超市管理系統(tǒng) 附源碼下載
這篇文章主要介紹了java實(shí)現(xiàn)簡(jiǎn)易超市管理系統(tǒng)(含源碼),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03Spring Boot如何優(yōu)雅的使用多線程實(shí)例詳解
這篇文章主要給大家介紹了關(guān)于Spring Boot如何優(yōu)雅的使用多線程的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05