摘要:訂單信息與訂單明細(xì)為一對(duì)多關(guān)系。例如先從單表查詢(xún),需要時(shí)再?gòu)年P(guān)聯(lián)表去關(guān)聯(lián)查詢(xún),大大提高數(shù)據(jù)庫(kù)性能,因?yàn)椴樵?xún)單表要比關(guān)聯(lián)查詢(xún)多張表速度要快。作用將關(guān)聯(lián)查詢(xún)信息映射到一個(gè)對(duì)象中。
MyBatis理解與掌握(關(guān)聯(lián)查詢(xún))
@(MyBatis)[Java, 框架, MyBatis]
一對(duì)一查詢(xún)案例:查詢(xún)所有訂單信息,關(guān)聯(lián)查詢(xún)下單用戶(hù)信息
從Order的角度,一個(gè)訂單對(duì)應(yīng)一個(gè)用戶(hù):order----->user (一對(duì)一)
從User的角度,一個(gè)用戶(hù)可以有多個(gè)訂單:user------>order (多對(duì)一)
場(chǎng)景需求:查詢(xún)訂單,同時(shí)關(guān)聯(lián)查詢(xún)用戶(hù)信息
-------------------------------表設(shè)計(jì)------------------------------------------
在t_orders(多方表)中增加一個(gè)字段user_id,作為外鍵
-------------------------------類(lèi)設(shè)計(jì)------------------------------------------
public class Order { private int oId; private int number; private User user; //省略get、set方法 } public class User { private Integer userId; private String userName; //省略get、set方法 }
-----------------------映射文件mapping.xml-----------------------
方法一:嵌套結(jié)果
association標(biāo)簽可用的屬性如下:
property:對(duì)象屬性的名稱(chēng) javaType:對(duì)象屬性的類(lèi)型 column:所對(duì)應(yīng)的外鍵字段名稱(chēng) select:使用另一個(gè)查詢(xún)封裝的結(jié)果 columnPrefix:當(dāng)連接多表時(shí),你將不得不使用列別名來(lái)避免ResultSet中的重復(fù)列名。指定columnPrefix允許你映射列名到一個(gè)外部的結(jié)果集中。
執(zhí)行過(guò)程:
DEBUG [main] - ==> Preparing: select t_orders.order_id, t_orders.order_number, t_user.id, t_user.user_name, t_user.user_address from t_orders,t_user WHERE t_orders.user_id = t_user.id and t_orders.order_id = ? DEBUG [main] - ==> Parameters: 1(Integer) TRACE [main] - <== Columns: order_id, order_number, id, user_name, user_address TRACE [main] - <== Row: 1, 30, 1, zhangsan, 北京 DEBUG [main] - <== Total: 1 打印查詢(xún)結(jié)果對(duì)象: Order [oId=1, number=30, user=User [userId=1, userName=zhangsan]]方法二:嵌套查詢(xún)
通過(guò)執(zhí)行另外一個(gè)SQL映射語(yǔ)句來(lái)返回預(yù)期的復(fù)雜類(lèi)型
---------------------------java代碼---------------------
@Test public void test() { SqlSession session = DBUtil.getSession(); Order order = session.selectOne("getOrder",1 ); System.out.println("打印查詢(xún)結(jié)果對(duì)象:"+order); }
--------------------------sql執(zhí)行過(guò)程-------------------------
DEBUG [main] - ==> Preparing: select order_id, order_number, user_id from t_orders WHERE order_id = ? DEBUG [main] - ==> Parameters: 1(Integer) TRACE [main] - <== Columns: order_id, order_number, user_id TRACE [main] - <== Row: 1, 30, 3 DEBUG [main] - ====> Preparing: select user_id as userId , user_name as userName from t_user WHERE user_id=? DEBUG [main] - ====> Parameters: 3(Integer) TRACE [main] - <==== Columns: userId, userName TRACE [main] - <==== Row: 3, wangwu DEBUG [main] - <==== Total: 1 DEBUG [main] - <== Total: 1 打印查詢(xún)結(jié)果對(duì)象:Order [oId=1, number=30, user=User [userId=3, userName=wangwu]]
__注意__:我們有兩個(gè)查詢(xún)語(yǔ)句:一個(gè)來(lái)加載order,另外一個(gè)來(lái)加載user。
這種方式很簡(jiǎn)單, 但會(huì)產(chǎn)生 “N+1 查詢(xún)問(wèn)題”。概括地講,N+1 查詢(xún)問(wèn)題可以是這樣引起的:
(1)你執(zhí)行了一個(gè)多帶帶的 SQL 語(yǔ)句來(lái)獲取結(jié)果列表(就是“+1”)。 (2)假設(shè)返回的是一個(gè)集合,集合中的每個(gè)元素對(duì)應(yīng)了一條記錄,你還需要執(zhí)行了一個(gè)查詢(xún)語(yǔ)句來(lái)為每條記錄加載細(xì)節(jié)(就是“N”)。
MyBatis 延遲加載是一種處理方式,然而,如果你加載一個(gè)列表,之后迅速迭代來(lái)訪(fǎng)問(wèn)嵌套的數(shù)據(jù),你會(huì)調(diào)用所有的延遲加載,問(wèn)題沒(méi)有解決。
方法三:增加一個(gè)包含訂單信息和用戶(hù)信息的類(lèi),用這個(gè)類(lèi)作為返回類(lèi)型 resultTypepublic class OrdersCustom extends Orders { private String username ; // 用戶(hù)名稱(chēng) private String address ; // 用戶(hù)地址 省略get、set方法 }
總結(jié):定義專(zhuān)門(mén)的po類(lèi)作為輸出類(lèi)型,其中定義了sql查詢(xún)結(jié)果集所有的字段。此方法較為簡(jiǎn)單,企業(yè)中普遍使用。
案例:通過(guò)訂單id查詢(xún)訂單信息及訂單下的訂單明細(xì)信息。
訂單信息與訂單明細(xì)為一對(duì)多關(guān)系。
---------------------------類(lèi)設(shè)計(jì)----------------------------------------
private int oId; private int number; //訂單編號(hào) private User user; //用戶(hù)信息 private Listorderdetails; //訂單詳情信息 //省略get、set方法 }
-------------------------映射文件-----------------------------
方法一:嵌套結(jié)果使用繼承extends,上面的
打印查詢(xún)結(jié)果對(duì)象:Order [oId=1, number=30000001, user=User [userId=3, userName=wangwu], orderdetails=[Orderdetail [odId=1, itemsId=2, itemsNum=30], Orderdetail [odId=2, itemsId=1, itemsNum=32]]]方法二:嵌套查詢(xún)
---------------------------java代碼---------------------
@Test public void test() { SqlSession session = DBUtil.getSession(); Order order = session.selectOne("getOrder",1 ); System.out.println("打印查詢(xún)結(jié)果對(duì)象:"+order); }
------------------------sql執(zhí)行結(jié)果-----------------------
打印查詢(xún)結(jié)果對(duì)象:Order [oId=1, number=30000001, user=User [userId=3, userName=wangwu], orderdetails=[Orderdetail [odId=1, itemsId=2, itemsNum=30], Orderdetail [odId=2, itemsId=1, itemsNum=32]]]
案例:查詢(xún)用戶(hù)購(gòu)買(mǎi)的商品信息
需要查詢(xún)所有用戶(hù)信息,關(guān)聯(lián)查詢(xún)訂單及訂單明細(xì)信息,訂單明細(xì)信息中關(guān)聯(lián)查詢(xún)商品信息
分析:
需要關(guān)聯(lián)查詢(xún)映射的信息是:訂單、訂單明細(xì)、商品信息
訂單:一個(gè)用戶(hù)對(duì)應(yīng)多個(gè)訂單,使用 collection 映射到用戶(hù)對(duì)象的訂單列表屬性中
訂單明細(xì):一個(gè)訂單對(duì)應(yīng)多個(gè)明細(xì),使用 collection 映射到訂單對(duì)象中的明細(xì)屬性中
商品信息: 一個(gè)訂單明細(xì)對(duì)應(yīng)一個(gè)商品, 使用 association 映射到訂單明細(xì)對(duì)象的商品屬性中。
---------------------------類(lèi)設(shè)計(jì)-----------------------------------
public class User { private Integer userId; private String userName; private Listorders; //訂單列表 } public class Order { private int oId; private int number; //訂單編號(hào) private List orderdetails; //訂單詳情信息 } public class Orderdetail { private int odId; private Items item; //商品信息 private int itemsNum; //商品數(shù)量 } public class Items { private int itemId; private String itemName; //商品名稱(chēng) }
-----------------------------映射文件--------------------------------------
---------------------------java代碼---------------------
@Test public void test() { SqlSession session = DBUtil.getSession(); Listusers = session.selectList("getUser"); for (User user : users) { System.out.println("打印用戶(hù)信息:"+user); } }
------------------------sql執(zhí)行結(jié)果-----------------------
打印用戶(hù)信息:User [userId=1, userName=zhangsan, orders=[Order [oId=1, number=30000001, orderdetails=[Orderdetail [odId=1, item=Items [itemId=2, itemName=香蕉], itemsNum=30], Orderdetail [odId=2, item=Items [itemId=1, itemName=蘋(píng)果], itemsNum=32]]], Order [oId=3, number=30000003, orderdetails=[Orderdetail [odId=3, item=Items [itemId=3, itemName=橘子], itemsNum=25]]]]] 打印用戶(hù)信息:User [userId=3, userName=wangwu, orders=[Order [oId=4, number=30000004, orderdetails=[Orderdetail [odId=4, item=Items [itemId=3, itemName=橘子], itemsNum=45]]]]]自關(guān)聯(lián) 延遲加載
什么是延遲加載
resultMap可實(shí)現(xiàn)高級(jí)映射(使用association、collection實(shí)現(xiàn)一對(duì)一及一對(duì)多映射),association、collection具備延遲加載功能。
例如:先從單表查詢(xún),需要時(shí)再?gòu)年P(guān)聯(lián)表去關(guān)聯(lián)查詢(xún),大大 提高數(shù)據(jù)庫(kù)性能 ,因?yàn)椴樵?xún)單表要比關(guān)聯(lián)查詢(xún)多張表速度要快。
mybatis框架默認(rèn)不支持延遲加載功能,如果想要使用,需要啟用延遲加載功能
默認(rèn)框架會(huì)采用侵入式的延遲加載:
如果查詢(xún)主動(dòng)方數(shù)據(jù),而不使用,那么關(guān)聯(lián)數(shù)據(jù)是不會(huì)被查詢(xún)的。
如果使用了主動(dòng)方的數(shù)據(jù),那么關(guān)聯(lián)數(shù)據(jù)即使沒(méi)有使用也會(huì)被查詢(xún)。
可以禁用侵入式延遲加載功能
綜上所述,在主配置文件mybatis-config.xml中做如下配置:
注意一個(gè)異常:Caused by: org.xml.sax.SAXParseException; lineNumber: 36; columnNumber: 17; 元素類(lèi)型為 "configuration" 的內(nèi)容必須匹配 "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)"。
在關(guān)聯(lián)的元素(association ,collection ,discriminator)中,我們存在一個(gè)屬性: fetchType來(lái)決定是否需要延遲加載,如果配置它,它將覆蓋掉原有在MyBatis設(shè)置的策略。
對(duì)于它而言,它有兩個(gè)取值:
* lazy: 延遲加載(默認(rèn)) * eager:即刻加載
由它來(lái)決定是否需要延遲或者即刻加載。
總結(jié) resultType作用:
將查詢(xún)結(jié)果按照 sql 列名 pojo 屬性名一致性映射到 pojo 中。
場(chǎng)合:
常見(jiàn)一些明細(xì)記錄的展示, 比如用戶(hù)購(gòu)買(mǎi)商品明細(xì), 將關(guān)聯(lián)查詢(xún)信息全部展示在頁(yè)面時(shí),此時(shí)可直接使用 resultType 將每一條記錄映射到 pojo 中, 在前端頁(yè)面遍歷 list ( list 中是 pojo )即可。
resultMap使用 association 和 collection 完成一對(duì)一和一對(duì)多高級(jí)映射 (對(duì)結(jié)果有特殊的映射要求) 。
association作用:
將關(guān)聯(lián)查詢(xún)信息映射到一個(gè) pojo 對(duì)象中。
場(chǎng)合:
為了方便查詢(xún)關(guān)聯(lián)信息可以使用 association 將關(guān)聯(lián)訂單信息映射為用戶(hù)對(duì)象的 pojo 屬性中,比如:查詢(xún)訂單及關(guān)聯(lián)用戶(hù)信息。使用 resultType 無(wú)法將查詢(xún)結(jié)果映射到 pojo 對(duì)象的 pojo 屬性中,根據(jù)對(duì)結(jié)果集查詢(xún)遍歷的需要選擇使用 resultType 還是 resultMap 。
collection作用:
將關(guān)聯(lián)查詢(xún)信息映射到一個(gè) list 集合中。
場(chǎng)合:
為了方便查詢(xún)遍歷關(guān)聯(lián)信息可以使用 collection 將關(guān)聯(lián)信息映射到 list 集合中,比如:查詢(xún)用戶(hù)權(quán)限范圍模塊及模塊下的菜單,可使用 collection 將模塊映射到模塊 list 中,將菜單列表映射到模塊對(duì)象的菜單 list 屬性中, 這樣的作的目的也是方便對(duì)查詢(xún)結(jié)果集進(jìn)行遍歷查詢(xún)。
如果使用 resultType 無(wú)法將查詢(xún)結(jié)果映射到 list 集合中。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/77174.html
摘要:容器自動(dòng)完成裝載,默認(rèn)的方式是這部分重點(diǎn)在常用模塊的使用以及的底層實(shí)現(xiàn)原理。 對(duì)于那些想面試高級(jí) Java 崗位的同學(xué)來(lái)說(shuō),除了算法屬于比較「天方夜譚」的題目外,剩下針對(duì)實(shí)際工作的題目就屬于真正的本事了,熱門(mén)技術(shù)的細(xì)節(jié)和難點(diǎn)成為了主要考察的內(nèi)容。 這里說(shuō)「天方夜譚」并不是說(shuō)算法沒(méi)用,不切實(shí)際,而是想說(shuō)算法平時(shí)其實(shí)很少用到,甚至面試官都對(duì)自己出的算法題一知半解。 這里總結(jié)打磨了 70 道...
摘要:語(yǔ)句在代碼中硬編碼,造成代碼不易于維護(hù),實(shí)際應(yīng)用變化的可能較大,變動(dòng)需要改變代碼。對(duì)結(jié)果集解析存在硬編碼查詢(xún)列名,變化導(dǎo)致解析代碼變化,系統(tǒng)不易于維護(hù),如果能將數(shù)據(jù)庫(kù)記錄封裝成對(duì)象解析比較方便。 MyBatis理解與掌握(簡(jiǎn)介) @(MyBatis)[Java, 框架, MyBatis] 簡(jiǎn)介 ??Mybatis是一個(gè)數(shù)據(jù)持久層框架,MyBatis消除了幾乎所有的JDBC代碼和參數(shù)的手...
摘要:理解與掌握緩存框架一級(jí)緩存默認(rèn)就可以使用框架處理緩存是依賴(lài)映射,的內(nèi)部緩存使用一個(gè),為語(yǔ)句。一級(jí)緩存的作用域是一個(gè),一旦發(fā)生變化,一級(jí)緩存失敗在同一個(gè)中,執(zhí)行相同的查詢(xún),第一次會(huì)去查詢(xún)數(shù)據(jù)庫(kù),并寫(xiě)到緩存中第二次直接從緩存中取。 MyBatis理解與掌握(緩存) @(MyBatis)[Java, 框架, MyBatis] 一級(jí)緩存(SqlSession) 默認(rèn)就可以使用 框架處理緩存是 ...
摘要:輸入?yún)?shù)類(lèi)型指定輸入?yún)?shù)類(lèi)型,通過(guò)從輸入對(duì)象中獲取參數(shù)值放置在中。查詢(xún)結(jié)果處理指定輸出結(jié)果類(lèi)型,將查詢(xún)結(jié)果的一行記錄數(shù)據(jù)映射為指定類(lèi)型的對(duì)象。 MyBatis理解與掌握(輸入與輸出) @(MyBatis)[Java, 框架, MyBatis] 占位符和拼接 {}:占位符 能防止sql注入問(wèn)題,所一能盡量用#{}就盡量用#{}用來(lái)傳入?yún)?shù),sql在解析的時(shí)候會(huì)加上 當(dāng)成字符串來(lái)解析 ,...
摘要:本文速覽本篇文章是我為接下來(lái)的源碼分析系列文章寫(xiě)的一個(gè)導(dǎo)讀文章。年該項(xiàng)目從基金會(huì)遷出,并改名為。同期,停止維護(hù)。符號(hào)所在的行則是表示的執(zhí)行結(jié)果。同時(shí),使用無(wú)需處理受檢異常,比如。另外,把寫(xiě)在配置文件中,進(jìn)行集中管理,利于維護(hù)。 1.本文速覽 本篇文章是我為接下來(lái)的 MyBatis 源碼分析系列文章寫(xiě)的一個(gè)導(dǎo)讀文章。本篇文章從 MyBatis 是什么(what),為什么要使用(why),...
閱讀 1362·2021-11-22 15:25
閱讀 3354·2021-10-21 09:38
閱讀 1572·2021-10-19 13:21
閱讀 998·2021-09-06 15:00
閱讀 1678·2019-08-30 15:44
閱讀 2591·2019-08-29 15:40
閱讀 3444·2019-08-29 13:44
閱讀 2047·2019-08-26 16:56