关联查询---Mybatis学习笔记(九)
商品訂單數據模型
注意:分析數據庫表和數據庫表之間的關系可以先通過數據庫中的主外鍵關系來分析,然后通過業務中的實際的關系來分析。
1.一對一查詢
需求:
查詢訂單信息,關聯查詢創建訂單的用戶信息
分析需求:
因為一個訂單信息只會是一個人下的訂單,所以從查詢訂單信息出發關聯查詢用戶信息為一對一查詢。如果從用戶信息出發查詢用戶下的訂單信息則為一對多查詢,因為一個用戶可以下多個訂單。
1.使用ResultType實現
1.sql語句:
select orders.*,user.username,user.birthday,user.sex,user.address from orders,user where orders.user_id = user.id;2.pojo類:
將上邊的sql語句的查詢結果映射到pojo中,pojo必須包括所有的查詢列名。
原始的Orders.java不能映射全部的字段,需要新創建一個pojo繼承Order.java類。(一般是繼承包括查詢字段較多的pojo類)
orders類:
public class Orders {private Integer id;private Integer userId;private String number;private Date createtime;private String note;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId = userId;}public String getNumber() {return number;}public void setNumber(String number) {this.number = number == null ? null : number.trim();}public Date getCreatetime() {return createtime;}public void setCreatetime(Date createtime) {this.createtime = createtime;}public String getNote() {return note;}public void setNote(String note) {this.note = note == null ? null : note.trim();}@Overridepublic String toString() {return "Orders [id=" + id + ", userId=" + userId + ", number=" + number+ ", createtime=" + createtime + ", note=" + note + "]";}OrdersCustom.java
public class OrdersCustom extends Orders{private String username;private Date birthday;private String sex;private String address;public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return "OrdersCustom [username=" + username + ", birthday=" + birthday + ", sex=" + sex + ", address=" + address+ ", getId()=" + getId() + ", getUserId()=" + getUserId() + ", getNumber()=" + getNumber()+ ", getCreatetime()=" + getCreatetime() + ", getNote()=" + getNote() + "]";}}3.mapper.xml文件
<mapper namespace="com.huihui.mapper.OrdersCustomMapper"><!-- 查詢訂單關聯查詢用戶 --><select id="findOrderUser" resultType="com.huihui.pojo.OrdersCustom">select orders.*,user.username,user.birthday,user.sex,user.address from orders,user where orders.user_id = user.id </select> </mapper>4.mapper接口:
public interface OrdersCustomMapper {//查詢訂單關聯查詢用戶public List<OrdersCustom> findOrderUser() throws Exception; }5.測試:
public class OrdersCustomMapperTest {private SqlSessionFactory sqlSessionFactory;@Before// 此方法是運行下面的測試用例的方法之前執行的public void setUp() throws Exception {// 創建sqlSessionFactory// mybatis配置文件路徑String resource = "SqlMapConfig.xml";// 得到配置文件流InputStream inputStream = Resources.getResourceAsStream(resource);// 創建會話工廠,傳入mybatis的配置文件信息sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);}@Testpublic void testFindOrdersUser() throws Exception{SqlSession sqlSession = sqlSessionFactory.openSession();//創建代理對象OrdersCustomMapper ordersMapperCustom = sqlSession.getMapper(OrdersCustomMapper.class);//調用mapper的方法List<OrdersCustom> list = ordersMapperCustom.findOrderUser();for (OrdersCustom ordersCustom : list) {System.out.println(ordersCustom);}System.out.println(list.size());sqlSession.close();}}2.使用ResultMap實現
1.sql語句(同ResultType實現的sql語句一樣):
2.pojo類
使用resultMap將查詢的結果中的訂單信息映射到Orders對象中,在orders類中添加User屬性,將關聯查詢出來的用戶信息映射到Order對象中的user屬性中。
在Orders類中加入User屬性,user屬性中用于存儲關聯查詢的用戶信息,因為訂單關聯查詢用戶是一對一關系,所以這里使用單個User對象存儲關聯查詢的用戶信息。
Order類:
public class Orders {private Integer id;private Integer userId;private String number;private Date createtime;private String note;//用戶信息private User user;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId = userId;}public String getNumber() {return number;}public void setNumber(String number) {this.number = number == null ? null : number.trim();}public Date getCreatetime() {return createtime;}public void setCreatetime(Date createtime) {this.createtime = createtime;}public String getNote() {return note;}public void setNote(String note) {this.note = note == null ? null : note.trim();}public User getUser() {return user;}public void setUser(User user) {this.user = user;}@Overridepublic String toString() {return "Orders [id=" + id + ", userId=" + userId + ", number=" + number+ ", createtime=" + createtime + ", note=" + note + ", user="+ user + "]";}}3.mapper.xml文件:
定義ResultMap:
需要關聯查詢映射的是用戶信息,使用association將用戶信息映射到訂單對象的用戶屬性中。
說明:
association:表示進行關聯查詢單條記錄
property:表示關聯查詢的結果存儲在com.huihui.pojo.Orders的user屬性中
javaType:表示關聯查詢的結果類型
<id property="id" column="user_id"/>:查詢結果的user_id列對應關聯對象的id屬性,這里是<id />表示user_id是關聯查詢對象的唯一標識。
<result property="username" column="username"/>:查詢結果的username列對應關聯對象的username屬性。
定義statement:
<!-- 查詢訂單信息關聯查詢用戶(使用ResultMap) --><select id="findOrderUserResultMap" resultMap="OrdersUserResultMap">select orders.*,user.username,user.birthday,user.sex,user.address fromorders,user where orders.user_id = user.id</select>4.mapper接口:
//查詢訂單關聯查詢用戶(使用ReusltMap)public List<Orders> findOrderUserResultMap() throws Exception;5.測試:
@Testpublic void testFindOrdersUserResultMap() throws Exception{SqlSession sqlSession = sqlSessionFactory.openSession();//創建代理對象OrdersCustomMapper ordersMapperCustom = sqlSession.getMapper(OrdersCustomMapper.class);//調用mapper的方法List<Orders> list = ordersMapperCustom.findOrderUserResultMap();for (Orders orders : list) {System.out.println(orders);}System.out.println(list.size());sqlSession.close();}3.resultType和resultMap實現一對一查詢小結:
實現一對一查詢:
定義專門的po類作為輸出類型,其中定義了sql查詢結果集所有的字段。此方法較為簡單,企業中使用普遍。
2.一對多查詢
需求:
查詢訂單及訂單明細的信息。
訂單與訂單明細為一對多關系。
分析需求:
查詢的主表:訂單表
查詢的關聯表:訂單明細表
在一對一查詢基礎上添加訂單明細表關聯即可。
使用ResultMap實現:
1.sql語句:
SELECTorders.*, USER .username,USER .sex,USER .address,orderdetail.id as orderdetail_id,orderdetail.items_id,orderdetail.items_num,orderdetail.orders_id FROMorders,USER,orderdetail WHEREorders.user_id = USER .id AND orderdetail.orders_id = orders.id;注意:這里查詢出orderdetail.id as orderdetail_id, 的作用是下面mapper.xml映射文件中的collection標簽中需要<id>中的唯一列。
查詢結果:
發現結果中的紅色方框中的記錄是重復的,但是后邊的items_id、items_num、orders_id列是不重復的。
那么這里如果使用resultType映射上面的查詢結果到pojo中的話,那么就會存在重復的信息。
解決方法:使用resultMap映射,將查詢結果映射到resultMap中設置的pojo類中,并且在pojo類中添加List<Orderdetail> orderdetails 屬性。那么最終會將訂單信息映射到orders中,訂單所對應的訂單明細就會映射到orders中的orderdetail屬性中。也就是說上圖中的查詢結果映射成的orders記錄數為2條(order信息不重復),每個orders中的orderdetails屬性存儲了該訂單所對應的訂單明細。
2.pojo類:
Orders.java類中添加如下內容:
注意還要重寫以下toString()方法,讓toString()方法打印出訂單詳情的信息。
3.mapper.xml映射文件:
定義ResultMap:
<!-- 查詢訂單及訂單明細的resultmap --><resultMap type="com.huihui.pojo.Orders" id="OrdersAndOrderDetailResultMap"><!-- 訂單信息 --><id column="id" property="id" /><result column="user_id" property="userId" /><result column="number" property="number" /><result column="createtime" property="createtime" /><result column="number" property="note" /><!-- 用戶信息 --><association property="user" javaType="com.huihui.pojo.User"><id column="user_id" property="id" /><result column="username" property="username" /><result column="birthday" property="birthday" /><result column="sex" property="sex" /><result column="address" property="address" /></association><!-- 訂單明細信息 --><!-- collection:對關聯查詢到的多條記錄映射到集合對象中 --><!-- property:將關聯查詢到多條記錄映射到com.huihui.pojo.Orders中的哪個屬性ofType:指定映射到集合屬性中pojo的類型--><collection property="orderdetails" ofType="com.huihui.pojo.Orderdetail"><!-- id:訂單明細的唯一標識property:將訂單明細的唯一標識列映射到com.huihui.pojo.Orderdetail中的哪個屬性--><id column="orderdetail_id" property="id"/><result column="items_id" property="itemsId"/><result column="items_num" property="itemsNum"/><result column="orders_id" property="ordersId"/></collection></resultMap>發現上面配置中的訂單信息和用戶信息之前在一對一映射(使用ResultMap)中定義ResultMap時定義的相同,那么可以使用繼承(extends)之前定義的ResultMap的方式:
<!-- 查詢訂單及訂單明細的resultmap --><resultMap type="com.huihui.pojo.Orders" id="OrdersAndOrderDetailResultMap" extends="OrdersUserResultMap"><!-- 訂單信息 --><!-- 用戶信息 --><!-- 訂單明細信息 --><!-- collection:對關聯查詢到的多條記錄映射到集合對象中 --><!-- property:將關聯查詢到多條記錄映射到com.huihui.pojo.Orders中的哪個屬性ofType:指定映射到集合屬性中pojo的類型--><collection property="orderdetails" ofType="com.huihui.pojo.Orderdetail"><!-- id:訂單明細的唯一標識property:將訂單明細的唯一標識列映射到com.huihui.pojo.Orderdetail中的哪個屬性--><id column="orderdetail_id" property="id"/><result column="items_id" property="itemsId"/><result column="items_num" property="itemsNum"/><result column="orders_id" property="ordersId"/></collection></resultMap>說明:
collection部分定義了查詢訂單明細信息。
collection:表示關聯查詢結果集
property=”orderdetails”:關聯查詢的結果集存儲在com.huihui.pojo.Orders上哪個屬性。
ofType=”com.huihui.pojo.Orderdetail”:指定關聯查詢的結果集中的對象類型即List中的對象類型。
<id />及<result/>的意義同一對一查詢。
定義statement:
<!-- 查詢訂單關聯查詢用戶及訂單明細(使用ResultMap) --><select id="findOrdersAndOrderDetailResultMap" resultMap="OrdersAndOrderDetailResultMap">SELECTorders.*, USER .username,USER .sex,USER .address,orderdetail.id as orderdetail_id,orderdetail.items_id,orderdetail.items_num,orderdetail.orders_idFROMorders,USER,orderdetailWHEREorders.user_id = USER .idANDorderdetail.orders_id = orders.id;</select>4.mapper接口:
//查詢訂單(關聯用戶)及訂單明細public List<Orders> findOrdersAndOrderDetailResultMap() throws Exception;5.測試:
@Testpublic void testFindOrdersAndOrderDetailResultMap() throws Exception{SqlSession sqlSession = sqlSessionFactory.openSession();//創建代理對象OrdersCustomMapper ordersMapperCustom = sqlSession.getMapper(OrdersCustomMapper.class);//調用mapper的方法List<Orders> list = ordersMapperCustom.findOrdersAndOrderDetailResultMap();for (Orders orders : list) {System.out.println(orders);}System.out.println(list.size());sqlSession.close();}小結:
mybatis使用resultMap的collection對關聯查詢的多條記錄映射到一個list集合屬性中。
如果使用resultType實現:
將訂單明細映射到orders中的orderdetails中,就需要自己手動處理(使用雙重循環遍歷去去掉重復記錄,將訂單明細信息存放到orderdetail中)
3.多對多查詢
需求:
查詢用戶及用戶購買的商品信息
分析需求:
查詢的主表是:用戶表
關聯表:由于用戶和商品沒有直接關聯,通過訂單和訂單明細進行關聯。所以關聯表為:orders、orderdetail、items
1.sql語句:
SELECTorders.*, USER .username,USER .sex,USER .address,orderdetail.id orderdetail_id,orderdetail.items_id,orderdetail.items_num,orderdetail.orders_id,items. NAME items_name,items.detail items_detail,items.price items_price FROMorders,USER,orderdetail,items WHEREorders.user_id = USER .id AND orderdetail.orders_id = orders.id AND orderdetail.items_id = items.id2.映射的pojo類:
映射思路:
將用戶信息映射到user中。
在user類中添加訂單列表屬性List<Orders> orderslist,將用戶創建的訂單映射到orderslist。
在Orders中添加訂單明細列表屬性List<OrderDetail>orderdetials,將訂單的明細映射到orderdetials。
在OrderDetail中添加Items屬性,將訂單明細所對應的商品映射到Items
User.java類中添加以下內容:
private List<Orders> orderslist;//訂單列表public List<Orders> getOrderslist() {return orderslist;}public void setOrderslist(List<Orders> orderslist) {this.orderslist = orderslist;}Orders.java類中添加以下內容:
//訂單明細private List<Orderdetail> orderdetails;public List<Orderdetail> getOrderdetails() {return orderdetails;}public void setOrderdetails(List<Orderdetail> orderdetails) {this.orderdetails = orderdetails;}Orderdetail.java類中增加以下內容:
private Items items;//訂單明細所對應的商品信息public Items getItems() {return items;}public void setItems(Items items) {this.items = items;}3.mapper.xml映射文件:
resultmap定義:
定義statement:
<!-- 查詢用戶及購買的商品信息,使用resultMap --><select id="findUserAndItemsResultMap" resultMap="UserAndItemsResultMap">SELECTorders.*, USER .username,USER .sex,USER .address,orderdetail.id orderdetail_id,orderdetail.items_id,orderdetail.items_num,orderdetail.orders_id,items. NAME items_name,items.detail items_detail,items.price items_priceFROMorders,USER,orderdetail,itemsWHEREorders.user_id = USER .idAND orderdetail.orders_id = orders.idAND orderdetail.items_id = items.id</select>4.mapper接口:
//查詢用戶及與用戶相關聯的商品信息public List<User> findUserAndItemsResultMap() throws Exception;5.測試:
@Testpublic void findUserAndItemsResultMap() throws Exception{SqlSession sqlSession = sqlSessionFactory.openSession();//創建代理對象OrdersCustomMapper ordersMapperCustom = sqlSession.getMapper(OrdersCustomMapper.class);//調用mapper的方法List<User> list = ordersMapperCustom.findUserAndItemsResultMap();for (User users : list) {System.out.println(users);}System.out.println(list.size());sqlSession.close();}多對多查詢總結:
將查詢用戶購買的商品信息明細清單,(用戶名、用戶地址、購買商品名稱、購買商品時間、購買商品數量)
針對上邊的需求就使用resultType將查詢到的記錄映射到一個擴展的pojo中,很簡單實現明細清單的功能。
一對多是多對多的特例,如下需求:
查詢用戶購買的商品信息,用戶和商品的關系是多對多關系。
需求1:
查詢字段:用戶賬號、用戶名稱、用戶性別、商品名稱、商品價格(最常見)
企業開發中常見明細列表,用戶購買商品明細列表,
使用resultType將上邊查詢列映射到pojo輸出。
需求2:
查詢字段:用戶賬號、用戶名稱、購買商品數量、商品明細(鼠標移上顯示明細)
使用resultMap將用戶購買的商品明細列表映射到user對象中。
總結:
使用resultMap是針對那些對查詢結果映射有特殊要求的功能,,比如特殊要求映射成list中包括 多個list。
ResultMap總結:
resultType:
作用:
將查詢結果按照sql列名pojo屬性名一致性映射到pojo中。
場合:
常見一些明細記錄的展示,比如用戶購買商品明細,將關聯查詢信息全部展示在頁面時,此時可直接使用resultType將每一條記錄映射到pojo中,在前端頁面遍歷list(list中是pojo)即可。
resultMap:
使用association和collection完成一對一和一對多高級映射(對結果有特殊的映射要求)。
association:
作用:
將關聯查詢信息映射到一個pojo對象中。
場合:
為了方便查詢關聯信息可以使用association將關聯訂單信息映射為用戶對象的pojo屬性中,比如:查詢訂單及關聯用戶信息。
使用resultType無法將查詢結果映射到pojo對象的pojo屬性中,根據對結果集查詢遍歷的需要選擇使用resultType還是resultMap。
collection:
作用:
將關聯查詢信息映射到一個list集合中。
場合:
為了方便查詢遍歷關聯信息可以使用collection將關聯信息映射到list集合中,比如:查詢用戶權限范圍模塊及模塊下的菜單,可使用collection將模塊映射到模塊list中,將菜單列表映射到模塊對象的菜單list屬性中,這樣的作的目的也是方便對查詢結果集進行遍歷查詢。
如果使用resultType無法將查詢結果映射到list集合中。
延遲加載
什么是延遲加載?
延遲加載:先從單表查詢、需要時再從關聯表去關聯查詢,大大提高數據庫性能,因為查詢單表要比關聯查詢多張表速度要快。
resultMap可以實現高級映射(使用association、collection實現一對一及一對多映射),association、collection具備延遲加載功能。
需求:
如果查詢訂單并且關聯查詢用戶信息。如果先查詢訂單信息即可滿足要求,當我們需要查詢用戶信息時再查詢用戶信息。把對用戶信息的按需去查詢就是延遲加載。
需求:
查詢訂單并且關聯查詢用戶信息
1.pojo類
Orders.java類中增加以下內容:
2.mapper.xml映射文件:
需要定義兩個mapper的方法對應的statement。
1、只查詢訂單信息
在查詢訂單的statement中使用association去延遲加載(執行)下邊的satatement(關聯查詢用戶信息)
<!-- 查詢訂單關聯查詢用戶信息,用戶信息需要延遲加載 --><select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingResultMap">select * from orders</select>2、關聯查詢用戶信息
通過上邊查詢到的訂單信息中user_id去關聯查詢用戶信息
使用UserMapper.xml中的findUserById
上邊先去執行findOrdersUserLazyLoading,當需要去查詢用戶的時候再去執行findUserById,通過resultMap的定義將延遲加載執行配置起來。
3、定義延遲加載的ResultMap
使用association中的select指定延遲加載去執行的statement的id。
說明:
association:
select=”findUserById”:指定關聯查詢sql為findUserById
column=”user_id”:關聯查詢時將users_id列的值傳入findUserById
最后將關聯查詢結果映射至com.huihui.pojo.User。
3.mapper接口:
//查詢訂單關聯查詢用戶(用戶信息是延遲加載)public List<Orders> findOrdersUserLazyLoading() throws Exception;3.測試:
執行過程:
1、執行上邊mapper方法(findOrdersUserLazyLoading),內部去調用com.huihui.mapper.OrdersCustomMapper中的findOrdersUserLazyLoading只查詢orders信息(單表)。
2、在程序中去遍歷上一步驟查詢出的List<Orders>,當我們調用Orders中的getUser方法時,開始進行延遲加載。
3、延遲加載,去調用UserMapper.xml中findUserbyId這個方法獲取用戶信息。
延遲加載配置:
mybatis默認沒有開啟延遲加載,需要在SqlMapConfig.xml中setting配置。
在mybatis核心配置文件中配置:lazyLoadingEnabled、aggressiveLazyLoading
| lazyLoadingEnabled | 全局性設置懶加載。如果設為‘false’,則所有相關聯的都會被初始化加載。 | true false | false |
| aggressiveLazyLoading | 當設置為‘true’的時候,懶加載的對象可能被任何懶屬性全部加載。否則,每個屬性都按需加載。 | true false | true |
在SqlMapConfig.xml中配置:
<settings><!-- 打開延遲加載的開關 --><setting name="lazyLoadingEnabled" value="true"/><!-- 將積極加載改為消極加載,即按需加載 --><setting name="aggressiveLazyLoading" value="false"/></settings>測試代碼:
@Testpublic void findOrdersUserLazyLoading() throws Exception{SqlSession sqlSession = sqlSessionFactory.openSession();//創建代理對象OrdersCustomMapper ordersMapperCustom = sqlSession.getMapper(OrdersCustomMapper.class);//調用mapper的方法List<Orders> list = ordersMapperCustom.findOrdersUserLazyLoading();//遍歷訂單列表for (Orders orders : list) {//執行getUser()去查詢用戶信息,這里實現按需加載User user = orders.getUser();System.out.println(user);}sqlSession.close();}結果:
延遲加載的思考:
不使用mybatis提供的延遲加載功能是否可以實現延遲加載?
實現方法:
針對訂單和用戶兩個表定義兩個mapper方法。
1、訂單查詢mapper方法
2、根據用戶id查詢用戶信息mapper方法
默認使用訂單查詢mapper方法只查詢訂單信息。
當需要關聯查詢用戶信息時再調用根據用戶id查詢用戶信息mapper方法查詢用戶信息。
延遲加載總結:
作用:
當需要查詢關聯信息時再去數據庫查詢,默認不去關聯查詢,提高數據庫性能。
只有使用resultMap支持延遲加載設置。
場合:
當只有部分記錄需要關聯查詢其它信息時,此時可按需延遲加載,需要關聯查詢時再向數據庫發出sql,以提高數據庫性能。
當全部需要關聯查詢信息時,此時不用延遲加載,直接將關聯查詢信息全部返回即可,可使用resultType或resultMap完成映射。
總結
以上是生活随笔為你收集整理的关联查询---Mybatis学习笔记(九)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 让Eclipse变得快点,取消valid
- 下一篇: 查询缓存---Mybatis学习笔记(十