java元婴期(25)----java进阶(mybatis(4)---高级映射查询缓存)
1.需要用到的數(shù)據(jù)模型(這是后面高級查詢需要用到的實例)
用戶表user:
???????? 記錄了購買商品的用戶信息
訂單表:orders
???????? 記錄了用戶所創(chuàng)建的訂單(購買商品的訂單)
訂單明細表:orderdetail:
???????? 記錄了訂單的詳細信息即購買商品的信息
商品表:items
???????? 記錄了商品信息
表與表之間的業(yè)務關(guān)系:
???????? 在分析表與表之間的業(yè)務關(guān)系時需要建立 在某個業(yè)務意義基礎上去分析。
先分析數(shù)據(jù)級別之間有關(guān)系的表之間的業(yè)務關(guān)系:
usre和orders:
- user---->orders:一個用戶可以創(chuàng)建多個訂單,一對多
- orders--->user:一個訂單只由一個用戶創(chuàng)建,一對一
orders和orderdetail:
- orders--->orderdetail:一個訂單可以包括 多個訂單明細,因為一個訂單可以購買多個商品,每個商品的購買信息在orderdetail記錄,一對多關(guān)系
- orderdetail--> orders:一個訂單明細只能包括在一個訂單中,一對一
orderdetail和itesm:
- orderdetail--->itesms:一個訂單明細只對應一個商品信息,一對一
- items--> orderdetail:一個商品可以包括在多個訂單明細 ,一對多
再分析數(shù)據(jù)庫級別沒有關(guān)系的表之間是否有業(yè)務關(guān)系:
orders和items:(涉及到數(shù)據(jù)庫的知識)
orders和items之間可以通過orderdetail表建立 關(guān)系。
?
高級查詢
1.一對一查詢
1.需求
查詢訂單信息,關(guān)聯(lián)查詢創(chuàng)建訂單的用戶信息
2.resultType
1.sql語句
- 確定查詢的主表:訂單表
- 確定查詢的關(guān)聯(lián)表:用戶表
???????? 關(guān)聯(lián)查詢使用內(nèi)鏈接?還是外鏈接?
???????? 由于orders表中有一個外鍵(user_id),通過外鍵關(guān)聯(lián)查詢用戶表只能查詢出一條記錄,可以使用內(nèi)鏈接。
SELECT orders.*,USER.username,USER.sex,USER.address FROMorders,USER WHERE orders.user_id = user.id2.創(chuàng)建pojo
將上邊sql查詢的結(jié)果映射到pojo中,pojo中必須包括所有查詢列名。
原始的Orders.java不能映射全部字段,需要新創(chuàng)建的pojo。
創(chuàng)建 一個pojo繼承包括查詢字段較多的po類。
?
3.mapper.xml
4.mapper.java
3.resultMap
1.sql語句
同resultType實現(xiàn)的sql(同上)
2.使用resultMap映射的思路
使用resultMap將查詢結(jié)果中的訂單信息映射到Orders對象中,在orders類中添加User屬性,將關(guān)聯(lián)查詢出來的用戶信息映射到orders對象中的user屬性中。
3.需要Orders類中添加user屬性
?
4.mapper.xml
定義resultMap
<!-- 訂單查詢關(guān)聯(lián)用戶的resultMap將整個查詢的結(jié)果映射到cn.itcast.mybatis.po.Orders中--><resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserResultMap"><!-- 配置映射的訂單信息 --><!-- id:指定查詢列中的唯 一標識,訂單信息的中的唯 一標識,如果有多個列組成唯一標識,配置多個idcolumn:訂單信息的唯 一標識 列property:訂單信息的唯 一標識 列所映射到Orders中哪個屬性--><id column="id" property="id"/><result column="user_id" property="userId"/><result column="number" property="number"/><result column="createtime" property="createtime"/><result column="note" property=note/><!-- 配置映射的關(guān)聯(lián)的用戶信息 --><!-- association:用于映射關(guān)聯(lián)查詢單個對象的信息property:要將關(guān)聯(lián)查詢的用戶信息映射到Orders中哪個屬性--><association property="user" javaType="cn.itcast.mybatis.po.User"><!-- id:關(guān)聯(lián)查詢用戶的唯 一標識column:指定唯 一標識用戶信息的列javaType:映射到user的哪個屬性--><id column="user_id" property="id"/><result column="username" property="username"/><result column="sex" property="sex"/><result column="address" property="address"/></association></resultMap>?
?
?
statement定義
5.mapper.java
?
3.resultType和resultMap實現(xiàn)一對一查詢小結(jié)
實現(xiàn)一對一查詢:
resultType:使用resultType實現(xiàn)較為簡單,如果pojo中沒有包括查詢出來的列名,需要增加列名對應的屬性,即可完成映射。
如果沒有查詢結(jié)果的特殊要求建議使用resultType。
resultMap:需要單獨定義resultMap,實現(xiàn)有點麻煩,如果對查詢結(jié)果有特殊的要求,使用resultMap可以完成將關(guān)聯(lián)查詢映射pojo的屬性中。
resultMap可以實現(xiàn)延遲加載,resultType無法實現(xiàn)延遲加載。(后面再詳解)
2.一對多查詢
1.需求
查詢訂單及訂單明細的信息。
2.sql語句
- 確定主查詢表:訂單表
- 確定關(guān)聯(lián)查詢表:訂單明細表
在一對一查詢基礎上添加訂單明細表關(guān)聯(lián)即可。
SELECTorders.*,USER.username,USER.sex,USER.address,orderdetail.id orderdetail_id,orderdetail.items_id,orderdetail.items_num,orderdetail.orders_idFROMorders,USER,orderdetailWHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id3.分析
使用resultType將上邊的 查詢結(jié)果映射到pojo中,訂單信息的就是重復。
要求:
對orders映射不能出現(xiàn)重復記錄。
?
在orders.java類中添加List<orderDetail> orderDetails屬性。
最終會將訂單信息映射到orders中,訂單所對應的訂單明細映射到orders中的orderDetails屬性中。
4.在orders中添加list訂單明細屬性
5.mapper.xml
6.resultMap定義
<!-- 訂單及訂單明細的resultMap使用extends繼承,不用在中配置訂單信息和用戶信息的映射--><resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersAndOrderDetailResultMap" extends="OrdersUserResultMap"><!-- 訂單信息 --><!-- 用戶信息 --><!-- 使用extends繼承,不用在中配置訂單信息和用戶信息的映射 --><!-- 訂單明細信息一個訂單關(guān)聯(lián)查詢出了多條明細,要使用collection進行映射collection:對關(guān)聯(lián)查詢到多條記錄映射到集合對象中property:將關(guān)聯(lián)查詢到多條記錄映射到cn.itcast.mybatis.po.Orders哪個屬性ofType:指定映射到list集合屬性中pojo的類型--><collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail"><!-- id:訂單明細唯 一標識property:要將訂單明細的唯 一標識 映射到cn.itcast.mybatis.po.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>7.mapper.java
8.小結(jié)
mybatis使用resultMap的collection對關(guān)聯(lián)查詢的多條記錄映射到一個list集合屬性中。(一對多,推薦使用這種)
使用resultType實現(xiàn):
將訂單明細映射到orders中的orderdetails中,需要自己處理,使用雙重循環(huán)遍歷,去掉重復記錄,將訂單明細放在orderdetails中。
3.多對多查詢
將查詢用戶購買的商品信息明細清單,(用戶名、用戶地址、購買商品名稱、購買商品時間、購買商品數(shù)量)
針對上邊的需求就使用resultType將查詢到的記錄映射到一個擴展的pojo中,很簡單實現(xiàn)明細清單的功能。
一對多是多對多的特例,如下需求:
查詢用戶購買的商品信息,用戶和商品的關(guān)系是多對多關(guān)系。
需求1:
查詢字段:用戶賬號、用戶名稱、用戶性別、商品名稱、商品價格(最常見)
企業(yè)開發(fā)中常見明細列表,用戶購買商品明細列表,
使用resultType將上邊查詢列映射到pojo輸出。
?
需求2:
查詢字段:用戶賬號、用戶名稱、購買商品數(shù)量、商品明細(鼠標移上顯示明細)
使用resultMap將用戶購買的商品明細列表映射到user對象中。
?
總結(jié):
使用resultMap是針對那些對查詢結(jié)果映射有特殊要求的功能,,比如特殊要求映射成list中包括 多個list。
4.resultMap總結(jié)
resultType:
作用:將查詢結(jié)果按照sql列名pojo屬性名一致性映射到pojo中。
場合:
???????? 常見一些明細記錄的展示,比如用戶購買商品明細,將關(guān)聯(lián)查詢信息全部展示在頁面時,此時可直接使用resultType將每一條記錄映射到pojo中,在前端頁面遍歷list(list中是pojo)即可。
resultMap:
???????? 使用association和collection完成一對一和一對多高級映射(對結(jié)果有特殊的映射要求)。
association:
作用:?將關(guān)聯(lián)查詢信息映射到一個pojo對象中。
場合:
???????? 為了方便查詢關(guān)聯(lián)信息可以使用association將關(guān)聯(lián)訂單信息映射為用戶對象的pojo屬性中,比如:查詢訂單及關(guān)聯(lián)用戶信息。
???????? 使用resultType無法將查詢結(jié)果映射到pojo對象的pojo屬性中,根據(jù)對結(jié)果集查詢遍歷的需要選擇使用resultType還是resultMap。? ? ??
collection:
作用:將關(guān)聯(lián)查詢信息映射到一個list集合中。
場合:
???????? 為了方便查詢遍歷關(guān)聯(lián)信息可以使用collection將關(guān)聯(lián)信息映射到list集合中,比如:查詢用戶權(quán)限范圍模塊及模塊下的菜單,可使用collection將模塊映射到模塊list中,將菜單列表映射到模塊對象的菜單list屬性中,這樣的作的目的也是方便對查詢結(jié)果集進行遍歷查詢。
???????? 如果使用resultType無法將查詢結(jié)果映射到list集合中。
查詢緩存
什么是查詢緩存
- mybatis提供查詢緩存,用于減輕數(shù)據(jù)壓力,提高數(shù)據(jù)庫性能。
- mybaits提供一級緩存,和二級緩存。
一級緩存是SqlSession級別的緩存。在操作數(shù)據(jù)庫時需要構(gòu)造 sqlSession對象,在對象中有一個數(shù)據(jù)結(jié)構(gòu)(HashMap)用于存儲緩存數(shù)據(jù)。不同的sqlSession之間的緩存數(shù)據(jù)區(qū)域(HashMap)是互相不影響的。
為什么要用緩存?
如果緩存中有數(shù)據(jù)就不用從數(shù)據(jù)庫中獲取,大大提高系統(tǒng)性能。
2.一級緩存
一級緩存工作原理
1.第一次發(fā)起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,如果沒有,從數(shù)據(jù)庫查詢用戶信息。
得到用戶信息,將用戶信息存儲到一級緩存中。
2.如果sqlSession去執(zhí)行commit操作(執(zhí)行插入、更新、刪除),清空SqlSession中的一級緩存,這樣做的目的為了讓緩存中存儲的是最新的信息,避免臟讀。
3.第二次發(fā)起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,緩存中有,直接從緩存中獲取用戶信息。
?
一級緩存測試
mybatis默認支持一級緩存,不需要在配置文件去配置。
按照上邊一級緩存原理步驟去測試。
@Testpublic void testCache1() throws Exception{SqlSession sqlSession = sqlSessionFactory.openSession();//創(chuàng)建代理對象UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//下邊查詢使用一個SqlSession//第一次發(fā)起請求,查詢id為1的用戶User user1 = userMapper.findUserById(1);System.out.println(user1);// 如果sqlSession去執(zhí)行commit操作(執(zhí)行插入、更新、刪除),清空SqlSession中的一級緩存,這樣做的目的為了讓緩存中存儲的是最新的信息,避免臟讀。//更新user1的信息user1.setUsername("測試用戶22");userMapper.updateUser(user1);//執(zhí)行commit操作去清空緩存sqlSession.commit();//第二次發(fā)起請求,查詢id為1的用戶User user2 = userMapper.findUserById(1);System.out.println(user2);sqlSession.close();}?
一級緩存應用
正式開發(fā),是將mybatis和spring進行整合開發(fā),事務控制在service中。
一個service方法中包括 很多mapper方法調(diào)用。
service{
???????? //開始執(zhí)行時,開啟事務,創(chuàng)建SqlSession對象
???????? //第一次調(diào)用mapper的方法findUserById(1)
????????
???????? //第二次調(diào)用mapper的方法findUserById(1),從一級緩存中取數(shù)據(jù)
???????? //方法結(jié)束,sqlSession關(guān)閉
}
如果是執(zhí)行兩次service調(diào)用查詢相同 的用戶信息,不走一級緩存,因為session方法結(jié)束,sqlSession就關(guān)閉,一級緩存就清空。
3.二級緩存(了解)
原理
?
?
- 首先開啟mybatis的二級緩存。
- sqlSession1去查詢用戶id為1的用戶信息,查詢到用戶信息會將查詢數(shù)據(jù)存儲到二級緩存中。
- 如果SqlSession3去執(zhí)行相同 mapper下sql,執(zhí)行commit提交,清空該 mapper下的二級緩存區(qū)域的數(shù)據(jù)。
- sqlSession2去查詢用戶id為1的用戶信息,去緩存中找是否存在數(shù)據(jù),如果存在直接從緩存中取出數(shù)據(jù)。
- 二級緩存與一級緩存區(qū)別,二級緩存的范圍更大,多個sqlSession可以共享一個UserMapper的二級緩存區(qū)域。
UserMapper有一個二級緩存區(qū)域(按namespace分) ,其它mapper也有自己的二級緩存區(qū)域(按namespace分)。
每一個namespace的mapper都有一個二緩存區(qū)域,兩個mapper的namespace如果相同,這兩個mapper執(zhí)行sql查詢到數(shù)據(jù)將存在相同 的二級緩存區(qū)域中。
?
總結(jié)
以上是生活随笔為你收集整理的java元婴期(25)----java进阶(mybatis(4)---高级映射查询缓存)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java元婴期(23)----java进
- 下一篇: java元婴期(24)----java进