Mybatis中的collection、association来处理结果映射
最近几天闲下来,主动把之前的代码优化了一下:)
原处理
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 }
1 <select id="selectBInfoByEventId" parameterType="String" resultType="EntityA">
2 SELECT
3 B.phone AS phone,
4 B.time AS time,
5 U.name AS userName
6 FROM table_b B
7 LEFT JOIN user U ON U.phone = B.phone
8 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>
优化分析
- 在代码结构上,要避免在for循环中作查询处理。考虑将查询参数evenId从for循环中提取出来,做批量查询,然后再将查询结果设定到对应的实体类中。
- 在业务上,对于每一个UserEvent中的eventId,业务表A中必定对应有一条记录,而在业务表B和业务表C中则未必有与这个eventId关联的数据。因此,可以将业务表A作为主表,通过eventId与另外几个表关联查询。查询次数也由原来的至少四次减少为一次查询。
- 对于联合查询的结果,以UserEvent作为查询结果的实体类,使用Mybatis中的collection、association来处理结果映射。
- 另外,各业务表的查询中都有与用户表User的关联,考虑将各业务信息的查询处理创建为视图。这样不仅能简化联合查询中SQL语句,也可以隔离基础表的数据。
优化后的代码
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">
SELECT
A.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 cTime
FROM v_table_a A
LEFT JOIN v_table_b B ON B.eventId = A.eventId
LEFT 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. 复杂对象的映射解析
<!-- 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标签的使用
处理时间对比
http://www.cnblogs.com/quiet-snowy-day/p/6166340.html
Mybatis中的collection、association来处理结果映射的更多相关文章
- Mybatis中使用collection进行多对多双向关联示例(含XML版与注解版)
Mybatis中使用collection进行多对多双向关联示例(含XML版与注解版) XML版本: 实体类: @Data @NoArgsConstructor public class Course ...
- 谈一下思考,关于mybatis中<foreach collection="list">中list得来的原因 没看到官方说明
<foreach> 是在sql语句中进行多个id查询 时用到的,因为mybatis代替jdbc和hibernate, 使用 在xml文件中编写sql语句,这是一个标签文件.然后在 dao层 ...
- Mybatis中的collection和association一关系
collection 一对多和association的多对一关系 学生和班级的一对多的例子 班级类: package com.glj.pojo; import java.io.Serializable ...
- mybatis 中 foreach collection的三种用法(转)
文章转自 https://blog.csdn.net/qq_24084925/article/details/53790287 oreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集 ...
- mybatis 中 foreach collection的三种用法
foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach元素的属性主要有 item,index,collection,open,separator,close. ...
- Mybatis 中 foreach collection 的三种用法
foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach元素的属性主要有 item,index,collection,open,separator,close. ...
- mybatis中foreach collection的三种用法
foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach元素的属性主要有 item,index,collection,open,separator,close. ...
- MyBatis 中 resultMap 详解
resultMap 是 Mybatis 最强大的元素之一,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中.如在实际应用中,有一个表为(用户角色表),通过查询用户表信息展示页面, ...
- mybatis中常见的问题总结
如下所有举例基于springboot+mybatis项目中,SSH使用mybatis的写法也一样,只是形式不同而已 问题1.org.apache.ibatis.binding.BindingExcep ...
随机推荐
- PHP 文件系统管理函数与 preg_replace() 函数过滤代码
案例:在带行号的代码至文件 crop.js 中.用两种方法去掉代码前面的行号,带行号的代码片段: 1.$(function(){ 2. //初始化图片区域 3. var myimg = new Ima ...
- 关于Shader的跨平台方案的考虑
Apple 推出 metal后,除了新的metal framewrok外,也多了一种新的shader语言,最近工作也做了一些metal移植的测试,主要还是现有引擎如何可以快速支持metal的解决方 ...
- 【Xamarin Doc】 Introduction to Storyboards 笔记
http://developer.xamarin.com/guides/ios/user_interface/introduction_to_storyboards/ Segues There are ...
- HTML: margin重疊現象的說明
2句話: ①相鄰的兩個普通元素,上下邊距,不是簡單的相加,而是取邊距較大的元素(若相邻的两个普通兄弟元素,它们的margin 值是一样的,则各取两个元素的margin 值的一半.)②关系为父子的两个d ...
- laravel 查看SQL语句
Route::get('/test-sql', function(){ DB::enableQueryLog(); $user = App\User::first(); return DB::getQ ...
- linux下常用的命令
一. tomcat tail -f ../logs/catalina.out 最新更新的日志(tomcat) cat ../logs/catalina ...
- 在Delphi下,如何使ShowMessage中的按钮中文化
如果你使用messagedlg(对showmessage也适用)可以汉化定义按钮caption的常量,具体操作步骤如下: 1. 打开文件consts.pas(在Delphi安装目录的/source ...
- Python之 continue继续循环和多重循环
Python之 continue继续循环 在循环过程中,可以用break退出当前循环,还可以用continue跳过后续循环代码,继续下一次循环. 假设我们已经写好了利用for循环计算平均分的代码: L ...
- Bootstrap 进度条媒体对象和条组
列表组组件 列表组组件用于显示一组列表的组件. //基本实例 <ul class="list-group"> <li class="list-group ...
- JS时间戳格式化日期时间 由于mysql数据库里面存储时间存的是时间戳,取出来之后,JS要格式化一下显示。
//时间戳转时间 function RiQi(sj) { var now = new Date(sj*1000); var year=now.getFullYear(); var month=now. ...