Mybatis中的collection、association来处理结果映射
生活随笔
收集整理的這篇文章主要介紹了
Mybatis中的collection、association来处理结果映射
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前不久的項目時間緊張,為了盡快完成原型開發,寫了一段效率相當低的代碼。 在代碼結構上,要避免在for循環中作查詢處理。考慮將查詢參數evenId從for循環中提取出來,做批量查詢,然后再將查詢結果設定到對應的實體類中。 在業務上,對于每一個UserEvent中的eventId,業務表A中必定對應有一條記錄,而在業務表B和業務表C中則未必有與這個eventId關聯的數據。因此,可以將業務表A作為主表,通過eventId與另外幾個表關聯查詢。查詢次數也由原來的至少四次減少為一次查詢。 對于聯合查詢的結果,以UserEvent作為查詢結果的實體類,使用Mybatis中的collection、association來處理結果映射。 另外,各業務表的查詢中都有與用戶表User的關聯,考慮將各業務信息的查詢處理創建為視圖。這樣不僅能簡化聯合查詢中SQL語句,也可以隔離基礎表的數據。
// 此處直接使用List,因為在業務上排除了重復數據的可能性。for (int i = 0; i < eventSize; i++) {eventIds.add(userEventList.get(i).getEventId());}Map<String, Object> paramsMap = new HashMap<String, Object>();paramsMap.put("eventIds", eventIds);paramsMap.put("phone", phone);List<UserEvent> eventInfoList = eventMapper.selectUserEventInfo(paramsMap);// 將查詢結果轉化為Map存儲,方便調用Map<String, UserEvent> eventInfoMap = new HashMap<String, UserEvent>();for(UserEvent event : eventInfoList){eventInfoMap.put(event.getEventId(), event);}UserEvent newEvent = null;String aTime = null;for(UserEvent event : roadEventList){ // 從查詢結果Map中取出補充信息,保存到原UserEvent對象中newEvent =eventInfoMap.get(event.getEventId());if(null != newEvent ){aTime = newEvent.getTime();event.setTime(aTime == null ? "" : sdfMd.format(sdfYmd.parse(aTime )));event.setIsActionB(newEvent.getIsActionB() == null ? "false" : newEvent.getIsActionB());event.setUserInfo(newEvent.getUserInfo());event.setListB(newEvent.getListB());event.setListC(newEvent.getListC());}}
open="(" separator="," close=")">#{eventId}</foreach></where>;</select>
<!-- 將各Java類的簡寫別名單獨放到文件mybatis.xml中,方便修改和管理?--><property?name="configLocation"?value="classpath:xml/mybatis.xml"?/>
? ?? <property?name="mapperLocations"?value="classpath:sql/*.xml"?/></bean> <!-- mybatis.xml文件 --><configuration><typeAliases><typeAlias alias="EntityA" type="com.xxxx.model.EntityA" /><typeAlias alias="EntityB" type="com.xxxx.model.EntityB" /><typeAlias alias="EntityC" type="com.xxxx.model.EntityC" /><typeAlias alias="User" type="com.xxxx.model.User" /></typeAliases></configuration>
最近幾天閑下來,主動把之前的代碼優化了一下:)
標簽:Java、Mybatis、MySQL 概況:本地系統從另外一個系統得到實體類集合List<UserEvent>,但是實體中只有eventId信息,其他屬性值均為空。 需要從數據庫中查詢數據,完善List<UserEvent>的信息并返回。 相關業務表以及對應的實體類,如下圖。(為了回避項目信息,相關業務內容均省略,以下表名、實體名、代碼變量名等均用字母ABC代替。)原處理
1.先來看代碼,乍一看邏輯清晰,符合正常思維習慣。 但是仔細查看發現,for循環中的每步處理都和數據查詢有關。假設有10次循環,每次循環中有4次數據庫連接查詢,一共需要連接數據庫40次。 每次數據庫連接都需要一定的開銷,隨著循環量不斷增加,處理時間將成倍增長,造成資源浪費。 1 String eventId = "";2 String aTime = "";3 for (UserEvent event : userEventList) {4 eventId = event.getEventId();5 6 // 獲取業務B信息7 List<EntityB> listB = mapperB.selectBInfoByEventId(eventId);8 event.setListB(listB);9 10 // 獲取業務C信息 11 List<EntityC> listC = mapperC.selectCInfoByEventId(eventId); 12 event.setListC(listC); 13 14 // 查看是否有業務B處理 15 EntityB entityB = mapperB.selectBInfoByPrimary(phone, eventId); 16 event.setIsActionB(null == entityB ? "false" : "true"); 17 18 // 獲取業務A和用戶信息 19 User userInfo = mapperA.selectEventUserInfoByEventId(eventId); 20 if(null != userInfo){ 21 aTime = userInfo.getTime(); 22 event.setTime(aTime == null ? "" : sdfMd.format(sdfYmd.parse(aTime))); 23 event.setUserInfo(userInfo); 24 } 25 }?
2.再來看查詢語句。 業務表A和業務表B沒有復雜的查詢。只有業務表C使用了一個子查詢,來獲取表內自身數據引用的信息。 各業務表數據都需要關聯到用戶表User。 1 <select id="selectBInfoByEventId" parameterType="String" resultType="EntityA">2 SELECT3 B.phone AS phone,4 B.time AS time,5 U.name AS userName6 FROM table_b B7 LEFT JOIN user U ON U.phone = B.phone8 WHERE B.event_id = #{eventId}9 ORDER BY B.time ASC 10 </select> 11 <select id="selectCInfoByEventId" parameterType="String" resultType="EntityC"> 12 SELECT 13 C.cmtId, 14 C.referId, 15 C.time, 16 U.name AS userName 17 ( SELECT TU.name FROM table_c TC 18 LEFT JOIN user TU ON TU.phone = TC.phone 19 WHERE TC.cmt_id = TC.refer_id 20 ) AS referName 21 FROM table_c C 22 LEFT JOIN user U ON C.phone = U.phone 23 WHERE C.event_id = #{eventId} 24 ORDER BY C.time ASC 25 <select id="selectEventUserInfoByEventId" parameterType="java.lang.String" resultType="User"> 26 SELECT 27 U.name, 28 U.picId, 29 A.time 30 FROM table_a A 31 LEFT JOIN user U ON U.phone = A.phone 32 WHERE A.event_id = #{eventId} 33 </select>?
優化分析
?
優化后的代碼?
int eventSize = userEventList.size();List<String> eventIds = new ArrayList<String>(); // 如果考慮去掉重復數據,可以使用集合Set,但是作為Mybatis的輸入參數,最后還是需要將Set轉化為List。// 此處直接使用List,因為在業務上排除了重復數據的可能性。for (int i = 0; i < eventSize; i++) {eventIds.add(userEventList.get(i).getEventId());}Map<String, Object> paramsMap = new HashMap<String, Object>();paramsMap.put("eventIds", eventIds);paramsMap.put("phone", phone);List<UserEvent> eventInfoList = eventMapper.selectUserEventInfo(paramsMap);// 將查詢結果轉化為Map存儲,方便調用Map<String, UserEvent> eventInfoMap = new HashMap<String, UserEvent>();for(UserEvent event : eventInfoList){eventInfoMap.put(event.getEventId(), event);}UserEvent newEvent = null;String aTime = null;for(UserEvent event : roadEventList){ // 從查詢結果Map中取出補充信息,保存到原UserEvent對象中newEvent =eventInfoMap.get(event.getEventId());if(null != newEvent ){aTime = newEvent.getTime();event.setTime(aTime == null ? "" : sdfMd.format(sdfYmd.parse(aTime )));event.setIsActionB(newEvent.getIsActionB() == null ? "false" : newEvent.getIsActionB());event.setUserInfo(newEvent.getUserInfo());event.setListB(newEvent.getListB());event.setListC(newEvent.getListC());}}
?
<resultMap id="UserMap" type="User"><result column="name" property="name" /><result column="picId" property="picId" /><result column="time" property="time" /></resultMap><resultMap id="BMap" type="EntityB"><id column="bPhone" property="phone" /><result column="bUserName" property="userName" /><result column="bTime" property="time" /></resultMap><resultMap id="CMap" type="EntityC"><id column="cmtId" property="cmtId" /><result column="referId" property="referId" /><result column="cUserName" property="userName" /><result column="referName" property="referName" /><result column="cTime" property="time" /></resultMap><resultMap id="EventResultMap" type="com.xxxx.bean.UserEvent"><id column="eventId" property="eventId" /><result column="time" property="time" /><result column="isActionB" property="isActionB" /><association property="userInfo" resultMap="UserMap" /><collection property="listB" resultMap="BMap" /><collection property="listC" resultMap="CMap" /></resultMap><select id="selectUserEventInfo" resultMap="EventResultMap">SELECTA.eventId,A.time,A.name,A.picId,CASE WHEN B.phone = #{phone} THEN "true" ELSE "false" END AS isActionB,B.phone AS bPhone,B.userName AS bUserName,B.time AS bTime,C.cmtId,C.referId,C.userName AS cUserName,C.referName AS referName,C.time AS cTimeFROM v_table_a ALEFT JOIN v_table_b B ON B.eventId = A.eventIdLEFT JOIN v_table_c C ON C.eventId = A.eventId<where>A.event_id in<foreach collection="eventIds" index="" item="eventId"open="(" separator="," close=")">#{eventId}</foreach></where>;</select>
?
編碼時需要注意的幾個地方
1. 復雜對象的映射解析
采用resultMap嵌套。其中,collection標簽表示映射一個集合,association標簽表示映射一個實體類, 標簽中的property屬性值對應的是,該集合/實體在查詢結果對象中的變量名。 對于各表中名稱相同的字段,需要建立別名,否則解析時無法確定各屬性與表字段的對應關系。 如:業務表B和業務表C中都有userName字段,在查詢語句中為為字段別名加了前綴來區分。 B.userName AS bUserName,?<result?column="bUserName"property="userName"/> C.userName AS cUserName,?<result?column="cUserName"?property="userName"?/> resultMap中type屬性表示標簽所包含內容對應映射的Java類。 該屬性可以寫類的全路徑(如:<resultMap?id="EventResultMap"?type="com.xxxx.bean.UserEvent">?), 也可以配置為簡寫的類名(如:<resultMap?id="UserMap"?type="User">?)。 簡寫的類名需要在xml配置文件中設置(如下),配好之后的簡寫類名可以在各個sql.xml中使用。 <!-- spring-mybatis.xml文件 --><!-- 配置sqlSessionFactory --><bean?id="sqlSessionFactory"?class="org.mybatis.spring.SqlSessionFactoryBean"><property?name="dataSource"?ref="dataSource"?/><!-- 將各Java類的簡寫別名單獨放到文件mybatis.xml中,方便修改和管理?--><property?name="configLocation"?value="classpath:xml/mybatis.xml"?/>
? ?? <property?name="mapperLocations"?value="classpath:sql/*.xml"?/></bean> <!-- mybatis.xml文件 --><configuration><typeAliases><typeAlias alias="EntityA" type="com.xxxx.model.EntityA" /><typeAlias alias="EntityB" type="com.xxxx.model.EntityB" /><typeAlias alias="EntityC" type="com.xxxx.model.EntityC" /><typeAlias alias="User" type="com.xxxx.model.User" /></typeAliases></configuration>
?
2. foreach標簽的使用
如果查詢接口只有一個參數,參數類型為list,則標簽中的collection屬性應該設定collection="list";參數類型為數組,則應設定為collection="array"。 如果查詢接口有多個參數,則最好通過Map來傳遞各參數。此時,foreach標簽的collection屬性應設置為,Map中表示集合參數的鍵。 如上面的代碼中,表示集合參數是eventIds,它在Map中的鍵為"eventIds"?,所以collection="eventIds"。處理時間對比
各表數據量在200、300條左右,List<UserEvent>集合記錄為13條。 雖然優化后的代碼行數有所增加,查詢結果解析略微復雜,但是十幾條數據的查詢已有2秒的差距。?
http://www.cnblogs.com/quiet-snowy-day/p/6166340.html
?
總結
以上是生活随笔為你收集整理的Mybatis中的collection、association来处理结果映射的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android逆向工程 初篇
- 下一篇: 组态王接入多比物联网云平台