目录
3.将查询结果映射到扩展类中(映射文件中的resultMap设置映射关系)
高级结果映射
主要解决多表关联,要求输出两个表信息的问题,或者是多个表的信息的问题
一、表与表之间的关系
一对一
一对多
多对多(本质上还是一对多)
二、一对一
首先创建两个表
淘宝中的个人账户 用户表 (登录名 密码 姓名 注册时间 状态 登录时间) create table b_user( id int not null primary key auto_increment, login_name varchar(20), paw varchar(20), create_date varchar(20), status int , last_login_date varchar(20) ) 用户详情表(身份证号 生日 联系电话 邮箱) create table b_user_info ( id int not null primary key auto_increment, user_id int , card_no varchar(18), birthday varchar(20), mobile varchar(20), email varchar(20) )
要求:查询用户列表、显示用户的登录信息以及用户的详细信息
分析:
1.两个表之间的关系是一对一的 ---即一个用户有一个用户的详细信息
2. 然后分析谁应该是主表谁是从表,因为用户的详细信息可能没有填写,因此我们可以得知 主表:b_user 从表:b_user_info
3.分析使用说明连接两个表
inner join b_user中没有完善信息的用户可能无法显示
left join b_user的信息全部显示,从表能关联上的也显示,关联不上的也显示以null填充
right join 跟left join 是相同的 但是我们一般都是比较先与left join
因此分析得出使用 left join
select * from b_user a left join b_user_info b on a.id=b.user_id
这样查询出来的结果为
我们发现查询出来有两个 id ---》 因此我们要进行别名设置来进行区分
select a.*,b.id detail_id,user_id,card_no,birthday,mobile,email from b_user a left join b_user_info b on a.id = b.user_id
步骤
1.创建实体类
BUser 和BUserInfo
但是我们是要查询两个都包含的
一般情况我们会考虑 创建第三个实体类将两个表的属性全部写进去(这样是可以实现的但是比较low 即然后两个表进行改动后这个表也要进行改动,耦合性太高---等于工资低)
因此我们使用创建第三个实体类(扩展类)【一般是创建在dto结尾的包中】,这个类描述了2个实体之间的关系
2.创建扩展类
扩展类继承主表 创建属性为从表属性
class BUserDto extends BUser{
//因为是一对一的直接创建一个成员变量为用户详细信息类
private BUserInfo info ;
}
3.将查询结果映射到扩展类中(映射文件中的resultMap设置映射关系)
<resultMap type="com.sofwin.dto.BUserDto" id="map2"> <id column="id" property="id"/> <result column="login_name" property="loginName"/> <result column="pwd" property="pwd"/> <result column="status" property="status"/> <result column="create_date" property="createDate"/> <result column="last_login_date" property="lastLoginDate"/> <!-- 自定义类型的属性映射 association :进行1对1结果映射 property:扩展类中自定义类型的属性的属性名 javaType:当前属性的类型(设置全限定类名或者别名) --> <association property="info" javaType="buserinfo"> <!--实体类的映射规则 用于映射主键 id主键列可以不用映射,但是映射可以提高查询结果的封装效率,因此我们一般进行映射 property对应的是buserinfo类中的属性 而column对应的是查询结果集的列名 --> <id column="detail_id" property="id"/> <result column="user_id" property="userId"/> <result column="card_no" property="cardNo"/> <result column="birthday" property="birthday"/> <result column="mobile" property="mobile"/> <result column="email" property="email"/> </association> </reusltMap> <select id="selectUserInfo" resultMap="map2"> select a.*,b.id detail_id,user_id,card_no,birthday,mobile,email from b_user a left join b_user_info b on a.id = b.user_id </select>
注意注意:
三、一对多
问题:显示订单信息,并关联显示订单详情
创建两个表
b_oredermain 订单主表
b_orderdetail 订单详情表b_ordermain 订单主表
CREATE TABLE b_ordermain( id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(20) NOT NULL, user_id INT, status INT, total INT ) b_orderdetal 订单明细表 CREATE TABLE b_orderdetail( id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, main_id INT, goods_id INT, price INT, num INT, total INT )
分析:
1.两个表之间的关系是一对多的 ---即一个订单主表有多个订单的详情表
2. 然后分析谁应该是主表谁是从表,因为是一个订单主表对应多个订单详情表,因此我们可以得知 主表:b_oredermain 从表:b_orderdetail
1.创建实体类 (get set省略了)
b_oredermain 订单主表 public class BOrdermain { private Integer id; private String orderNo; private Integer userId; private Integer status; private Integer total; } b_orderdetail 订单详情表 public class BOrderDetal { private Integer id; private Integer mainId; private Integer goodsId; private Integer price; private Integer num; private Integer total; }
2.编写sql语句
sql语句还是要注意相同的列名要进行别名 进行区分
select a.* ,b.id detail_id,goods_id,price,num,b.total xj from b_ordermain a left join b_orderdetail b on a.id = b.main_id;
3.创建扩展类 (get set方法省略)
public class OrderMainDto extends OrderMain{ private List<OrderDetail> details; }
这里是一对多 所以我们的属性是集合中存放多个订单详情表
4.映射Dto
<resultMap id="map3" type="com.sofwin.dto.OrderMainDto"> <id column="id" property="id"/> <result column="order_no" property="orderNo"/> <result column="user_id" property="userId"/> <result column="status" property="status"/> <result column="total" property="total"/> <!--对应一对多的结果映射采用 collection 集合类型的属性的映射都采用的是collection property :集合类型的属性的属性名 ofType :当属性的泛型 全限定类名或者别名 --> <collection property="details" ofType="orderdetail"> <!-- 每个orderdeail的映射规则 --> <id column="detail_id" property="id"/> <result column="goods_id" property="goodsId"/> <result column="price" property="price"/> <result column="num" property="num"/> <result column="xj" property="total"/> </collection> </resultMap> <select id="selectOrders" resultMap="map3"> select a.*,b.id detail_id,goods_id,price,num,b.total xj from b_ordermain a left join b_orderdetail b on a.id = b.main_id; </select>
总结---多表关联查询的结果映射步骤
1.首先使用java类来描述表间关系(Deo类中描述连个表之间的关系)
2.将查询结果映射到扩展类(映射文件中的resultMap设置映射关系)
具体步骤
1. 创建表
2.创建实体类
3.分析主表从表 以及是一对一 还是一对多
4.定义sql
5.创建扩展类
6.Dto映射
动态sql
1.主要是解决我们根据条件不同,sql语句会发送动态变化,而我们无法在xml的映射文件中进行条件判断或者是循环判断等等 。
2.并且动态sql还能让我实现事务的一致性 ----如果以前我们都是在java中进行循环来查找,如果第二个发生错误,第一个已经执行,并没有回滚,这就违背了我们事务的特性。
基于以上的情况我们引入了动态sql来解决这些问题
一、选择结构
1.1 if单条件选择
jstl语句:<c:if test="基于el表达式的逻辑表达式">sdfsdf</c:if>
mybatis: <if test="" >
要加入的sql语句
</if>
传入参数的三种情况 简单类型、自定义pojo、map类型
自定义pojo类型
test 逻辑表达式:
如果输入参数是自定义pojo类型,可以直接通过属性名进行判断
如果逻辑表达式为真 if标签中的sql语句就会和上面的sql语句进行拼接
<select id="selectUsers" parameterType="user" resultMap="map1" timeout="1000"> select id ids,name names,sex sexs from s_user where 1=1 (这个我们先这样 破坏了索引 --后面有解决方法) <if test="name!=null and name!=' ' " > and name like '%#{name}%' </if> <if test="sex!=null " > and sex like '%#{sex}%' </if>
简单类型
<select id="selectUsers" parameterType="string" resultMap="map1" timeout="1000"> select id ids,name names,sex sexs from s_user <!--如果输入的简单数据类型 ,_parameter 为当前输入参数的值--> <if test="_parameter" > where name like ' %#{value}%' </if>
map类型
List<User> selectUsers(@Param("name") String name,@Param("sex") Integer sex); 这两个是相同的 ---是等同于的
List<User> selectUsers(Map map);<select id="selectUsers" resultMap="map1" timeout="1000"> select id ids,name names,sex sexs from s_user where 1=1 <!-- 如果输入参数为map或者注解@Param类型,key当前输入参数的值 --> <if test="sex!=null"> and sex =#{sex} </if>
1.2 choose 多条件选择
语法
jstl
<c:choose>
<c:when test=" "> </c:when>
<c:when test=" "> </c:when>
....
<c:otherwise> </c:otherwise>
</c:choose>
mybatis
<choose>
<when test=" "> </when>
<when test=" "> </when>
....
<otherwise> </otherwise>
</choose>
<select id="selectUsers" resultMap="map1" timeout="1000"> select id ids,name names,sex sexs from s_user where 1=1 <choose> <when test="name!=null and name!=''"> and name like '%${name}%' </when> <when test="sex!=null"> and sex=#{sex} </when> <otherwise> and 2=2 </otherwise> </choose> </select>
二、循环结构
主要解决给定一个数组 按照数组汇总提供的id进行批量删除
{1,2,3,4}
语法
jstl
<c:foreach items="需要遍历的集合" var="当前对象" varStatus="获取索引">
循环体
</c:foreach>
mybatis
<foreach collection="需要遍历的集合" item="当前对象" index="当前索引" open="以什什么开头" close="循环以什么结尾" seperator="循环以什么分割">
</foreach>
<!--如果输入参数是集合 collection为list
如果输入参数是数组 collection为array
如果输入参数是ppjo或者map collection为属性名或者key
-->
数组
<delete id="removeUsers" parameterType="int"> delete from s_user where id in <foreach collection="array" item="id" open="(" close=")" separator=","> #{id} </foreach> </delete>
集合
<delete id="removeUsers" parameterType="int"> delete from s_user where id in <foreach collection="list" item="id" open="(" close=")" separator=","> #{id} </foreach> </delete>
POJO或者map
<delete id="removeUsers" parameterType="map"> delete from s_user where id in <!-- ids是map或者是popp中的数组或者集合的属性--> <foreach collection="ids" item="id" open="(" close=")" separator=","> #{id} </foreach> </delete>
三、扩展功能
3.1 where
自动增加where关键字,并去除第一个and,一般where标签内部需要使用选择结构
select id="selectUsers" resultMap="map1" timeout="1000">
select id ids,name names,sex sexs from s_user
<where>
<if test="name!=null and name!=''">
and name like '%${name}%'
</if>
<if test="sex!=null">
and sex=#{sex}
</if>
</where>
</select>
3.2 set
自动增加set关键字,并取出最后一个 ,只能用在update语句
<update id="updateUser" parameterType="user" >
update s_user
<set>
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="sex">
sex=#{sex},
</if>
</set>
where id=#{id}
</update>
3.3 trim
可以构建where和set
<!--
prefix:增加前缀
suffix:增加后缀
prefixOverrides:覆盖第一指定字符
suffixOverrides:覆盖最后一个字符
-->
<trim prefix="" suffix="" prefixOverrides="" suffixOverrides=""></trim>
<update id="updateUser" parameterType="user" > update s_user set的替换 <trim prefix="SeT" suffixOverrides=","> <if test="name!=null and name!=''"> name=#{name}, </if> <if test="sex"> sex=#{sex}, </if> </trim> where id=#{id} </update> where的替换 <select id="selectUsers" resultMap="map1" timeout="1000"> select <include refid="tableColumns"></include> from s_user <trim prefix="where" prefixOverrides="and"> <if test="name!=null and name!=''"> and name like '%${name}%' </if> <if test="sex!=null"> and sex=#{sex} </if> </trim> </select>
3.4 sql
定义sql片段,解耦合,即xml中存在模板配置 可以做出sql片段
<sql id="tableColumns">
id ids,name names,sex sexs
</sql>
3.5 include
引用某个sql片段
<select id="selectUsers" resultMap="map1" timeout="1000">
select
<include refid="tableColumns"></include>
from s_user
<where>
<if test="name!=null and name!=''">
and name like '%${name}%'
</if>
<if test="sex!=null">
and sex=#{sex}
</if>
</where>
</select>