前言
这次我们闲谈一下Mybatis高级映射,高级映射分为:一对一,一对多,多对多,接下来我们介绍一一介绍下来。
resultMap
resultMap :使用 association 和 collection 完成一对一和一对多以及多对多的高级映射(对结果有特殊的映射要求)。
association :作用:将关联查询信息映射到一个pojo对象中。如为了方便查询关联信息可以使用 association 将关联订单信息映射为用户对象的 pojo 属性中,比如:查询订单及关联用户信息。
使用 resultType 无法将查询结果映射到 pojo 对象的 pojo 属性中,根据对结果集查询遍历的需要选择使用 resultType 还是 resultMap 。
collection :作用:将关联查询信息映射到一个list集合中。如为了方便查询遍历关联信息可以使用 collection 将关联信息映射到 list 集合中,比如:查询用户权限范围模块及模块下的菜单,可使用 collection 将模块映射到模块 list 中,将菜单列表映射到模块对象的菜单 list 属性中,这样的作的目的也是方便对查询结果集进行遍历查询。如果使用 resultType 无法将查询结果映射到 list 集合中。
深度介绍
在介绍resultMap前,我们先讲解一下resultType如何完成一对一完成映射的,代码如下:
<mapper namespace="com.xxx.mybatis.dao.TeacherDao">
<select id="queryTeacherCascade" resultMap="teacher">
SELECT t.*,s.*,t.id t_id,s.id s_id from teacher t, student s WHERE t.id = s.tid;
</select>
</mapper>
相对resultMap这样的配置方式完成一对一比较简单,随后我们介绍一下如何使用resultMap如何完成。
我们先展示如何实现一对一的代码:
1.我们需要两个pojo类,代码如下:
@Getter
@Setter
public class T1 {
private Integer id;
private String bname;
private String author;
private T3 btype;
private Integer author_gender;
private Integer price;
private String description;
@Override
public String toString() {
return "T1{" +
"id=" + id +
", bname='" + bname + '\'' +
", author='" + author + '\'' +
", btype=" + btype +
", author_gender=" + author_gender +
", price=" + price +
", description='" + description + '\'' +
"}\n";
}
@Getter
@Setter
public class T3 {
private Integer id;
private String tname;
@Override
public String toString() {
return "T3{" +
"tid=" + id +
", tname='" + tname + '\'' +
"}\n";
}
2.随后在dao层中建立一个T1的接口,接口中定义一个查询的方法:
public interface T1Dao {
List<T1> qureyAll();
}
3.建立完成后,我们发现T3类就是T1中一个属性的类型,属于类中类,所以我们需要建立一个xml文件,代码如下:
<mapper namespace="com.xxx.mybatis.dao.T1Dao">
<resultMap id="book" type="com.xxx.mybatis.bean.T1">
<id column="id" property="id"/>
<result column="bname" property="bname"/>
<result column="author" property="author"/>
<result column="author_gender" property="author_gender"/>
<result column="price" property="price"/>
<result column="description" property="description"/>
<association property="btype" javaType="com.xxx.mybatis.bean.T3">
<id property="id" column="tid"/>
<result column="tname" property="tname"/>
</association>
</resultMap>
<select id="qureyAll" resultMap="book">
select T1.*,T3.*,T1.id bid ,T3.tid bt_id from T1,T3 where T1.btype=T3.tid;
</select>
</mapper>
此时我们看到了用到了assocation
这个标签了,这体现了一对一的映射,标签内则是T3类中与数据库的列名所映射,随后我们在后面可以写上查询语句,在mybatis_conf.xml中添加加载此mapper的代码<mapper resource="mapper/BookM.xml"/>
4.随后我们在测试类中,我们获取sqlSession后,则可以调用接口中的方法,代码:
T1Dao t1Dao=null;
t1Dao=MyBatisTools.getInstance().openSession().getMapper(T1Dao.class);
List<T1> t1List =t1Dao.qureyAll();
log.info("t1List"+t1List);
到这里,我们已经将一对一做出介绍,一对多和一对一的区别在于xml文件中使用的是collection
这个标签,而且有点类似Mysql中的多表查询,但在pojo类中却不是类中类的表现,而是在一个类中是一个集合,代码如下:
public class City {
private String cname;
// private Integer id;
private Integer pid;
public class Province {
private Integer id;
private String pname;
private List<City>cityLists;
随后我们展示一下xml中的区别,代码如下:
<mapper namespace="com.xxx.mybatis.dao.ProvinceDao">
<resultMap id="province" type="com.xxx.mybatis.bean.Province">
<id property="id" column="id"/>
<result property="pname" column="pname"/>
<collection property="cityLists" ofType="com.xxx.mybatis.bean.City">
<result property="cname" column="cname"/>
<result property="pid" column="pid"/>
</collection>
</resultMap>
<select id="queryAll" resultMap="province">
select p.*,c.*from province p,city c where p.id=c.pid;
</select>
</mapper>
到这里,我们已经将一对一做出介绍,一对多和一对一的区别在于xml文件中使用的是collection
这个标签,而且有点类似Mysql中的多表查询,但在pojo类中却不是类中类的表现,而是在一个类中是一个集合,代码如下:
public class City {
private String cname;
// private Integer id;
private Integer pid;
public class Province {
private Integer id;
private String pname;
private List<City>cityLists;
随后我们展示一下xml中的区别,代码如下:
<mapper namespace="com.xxx.mybatis.dao.ProvinceDao">
<resultMap id="province" type="com.xxx.mybatis.bean.Province">
<id property="id" column="id"/>
<result property="pname" column="pname"/>
<collection property="cityLists" ofType="com.xxx.mybatis.bean.City">
<result property="cname" column="cname"/>
<result property="pid" column="pid"/>
</collection>
</resultMap>
<select id="queryAll" resultMap="province">
select p.*,c.*from province p,city c where p.id=c.pid;
</select>
</mapper>
此时我们可以看到之前的标签和这个标签有所不同,此次使用的是collection
这个标签来映射一个类中的另外一个类。多对多和这个是相似的情况,我们可以在collection
中再加上association
这个标签,在此我们将不再细细的讲解。
当我们配置好xml后,获取sqlSession和之前的如出一辙,所以在此不再详细介绍。
浅谈动态sql
在这里我们再介绍一下动态sql如何使用,这里只介绍where、if、choos、when、trim,首先是where及一下的标签if与choose 和when,先看代码:
<select id="queryStudentByCondition" resultType="Student">
select * from student
<where>
<if test="sname != null">
sname = #{sname}
</if>
<if test="nickName != null">
and nick_name = #{nickName}
</if>
<if test="id != null">
and id = #{id}
</if>
</where>
</select>
<select id="queryStudentByChooseWhen" resultType="Student">
select * from student
<where>
<choose>
<when test="sname != null">
and sname = #{sname}
</when>
<when test="nickName != null">
and nick_name = #{nickName}
</when>
<otherwise>
and id = 5
</otherwise>
</choose>
</where>
</select>
我们看到在sql代码后加入了代码,而标签中一种是if标签,而另一种则是choose和when标签,都是为了减少之前的老代码中的if判断,减少了代码的累赘,但这两种有区别,if标签的话则是第一个if判断过后,还能执行后面的if判断,但是choose标签的话,满足第一个when标签后则不再执行后面的代码,相当于switch循环语句,中的break,但是otherwise中的代码则是必须执行的,这就是区别。随后就是trim标签,代码如下:
<update id="updateById" parameterType="Student">
update student
<!--
<set>
-->
<trim prefix="set" suffixOverrides=",">
<if test="sname != null">
sname = #{sname},
</if>
<if test="nickName != null">
nick_name = #{nickName},
</if>
</trim>
<!--
</set>
-->
where id = #{id}
</update>
代码中可以看到,trim应用于更新代码中,相当于set,trim有很多属性,这里使用了prefix属性赋值为set,而后面的suffisOverrides则是消除最后一个拼接sql语句后的逗号,至此几个动态sql的几个标签我们介绍完毕。