mybatis总结(三)(resultMap和高级映射-级联)

在真实的业务场景中,使用resultType进行输出映射,只有查询出来的列名和pojo(实体bean)中的属性名一致,该列才可以映射成功。简单来说也就是你的数据库字段和JavaBean里的字段名称必须一致才能映射成功。

当JavaBean中的字段名和数据库字段名称有不同的时候,或者是多表查询的时候,一般会使用resultMap。

什么是resultMap

 

resultMap是Mybatis最强大的元素,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中。

resultMap的作用

 

resultMap的作用是定义映射规则、级联的更新、定制类型转化器等。resultMap定义的主要是一个结果集的映射关系,也就是sql到java bean的映射关系定义,它也支持级联等特性。

resultMap的元素构成

 

resultMap元素的子元素:

<resultMap>
    <constructor>
        <idArg/>
        <arg>
    </constructor>
    <id/>
    <result/>
    <association/>
    <collection/>
    <discriminator>
        <case/>
    </discriminator>
</resultMap>

 resultMap的语法

 

<!--column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性-->
<resultMap id="唯一的标识" type="映射的pojo对象">
  <id column="表的主键字段,或者可以为查询语句中的别名字段" jdbcType="字段类型" property="映射pojo对象的主键属性" />
  <result column="表的一个字段(可以为任意表的一个字段)" jdbcType="字段类型" property="映射到pojo对象的一个属性(须为type定义的pojo对象中的一个属性)"/>
  <association property="pojo的一个对象属性" javaType="pojo关联的pojo对象">
    <id column="关联pojo对象对应表的主键字段" jdbcType="字段类型" property="关联pojo对象的主席属性"/>
    <result  column="任意表的字段" jdbcType="字段类型" property="关联pojo对象的属性"/>
  </association>
  <!-- 集合中的property须为oftype定义的pojo对象的属性-->
  <collection property="pojo的集合属性" ofType="集合中的pojo对象">
    <id column="集合中pojo对象对应的表的主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" />
    <result column="可以为任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属性" />  
  </collection>
</resultMap>

如果collection标签是使用嵌套查询,格式如下:

 <collection column="传递给嵌套查询语句的字段参数" property="pojo对象中集合属性" ofType="集合属性中的pojo对象" select="嵌套的查询语句" > 
 </collection>

注意:<collection>标签中的column:要传递给select查询语句的参数,如果传递多个参数,格式为column= ” {参数名1=表字段1,参数名2=表字段2} ;

resultMap的应用

比如,数据库中字段名称为id,name,age,sex 而对应java代码中pojo的属性名分别为id,username,age,sex。可以看出姓名列不一致,这个时候就需要使用resultMap来将字段名和属性名对应起来,进行手动配置封装,将结果映射到pojo中。

<!-- resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo -->
<!-- id:设置ResultMap的id -->
<resultMap type="user" id="userMap">
    <!-- 定义主键 ,非常重要。如果是多个字段,则定义多个id -->
    <!-- property:pojo里的属性名 column:数据库中的列名 -->
    <id property="id" column="id" />

    <!-- 定义普通属性 property:pojo里的属性名 column:数据库中的列名-->
    <result property="username" column="name" />
    <result property="age" column="age" />
    <result property="sex" column="sex" />
</resultMap>

<!-- resultMap:填入配置的resultMap标签的id值 -->
<select id="findUser" resultMap="userMap">
    select id,name,age,sex from user 
</select>

 级联

Mybatis的级联操作主要是针对一对多、多对一和多对多的情况而设定的。级联是在resultMap标签中配置的。级联并不是必须的,好处就是获取关联数据便捷,但如果级联过多会增加系统的复杂度,同时降低系统的性能。所以记录超过3层时,就不要考虑使用级联了,因为这样会造成多个对象的关联,导致系统的耦合、负载和难以维护。

一对一

业务场景:订单用户,一条订单信息只能对应一个用户,此为一对一。做法如下:

1. 改造订单的pojo类:

(添加User属性--User属性是一个引用类型,用于存储关联查询的用户信息,因为关联关系是一对一,所以只需要添加单个属性即可)

//订单类
pulic class Order{
    //原order属性
    private int id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;
    //新加user属性
    private User user;
    //下面省略get和set方法
}

//用户信息类
pulic void User{
    private int id;
    private String username;
    private String address;
    //下面省略get和set方法
}

2. 修改mapper.xml配置文件

(使用resultMap和association标签来实现一对一)

<resultMap type="order" id="orderUserResultMap">
    <!-- 第一步:配置Order类的对应关系 -->
    <!-- property:pojo里的属性名 column:数据库中的列名 -->
    <id property="id" column="id" />
    <result property="userId" column="user_id" />
    <result property="number" column="number" />
    <result property="createtime" column="createtime" />
    <result property="note" column="note" />

    <!-- 第二步:配置User类的对应关系 -->
    <!-- association :配置一对一属性 property:order里面的User属性名 javaType:属性类型-->
    <association property="user" javaType="user">
        <!-- id:声明主键,表示user_id是关联查询对象的唯一标识 -->
        <!-- 简单说就是:id标签:(property:user表的主键名称 column:对应Order表的外键名称) result标签下的都是user表的内容-->
        <id property="id" column="user_id" />
        <result property="username" column="username" />
        <result property="address" column="address" />
    </association>

</resultMap>

<!-- 一对一关联,查询订单,订单内部包含用户属性 -->
<select id="queryOrderUserResultMap" resultMap="orderUserResultMap">
    SELECT a.id,a.user_id,a.number,a.createtime,a.note,b.username,b.address from order a left join user b on a.user_id = b.id
</select>

3. 测试代码:

@Test
public void testQueryOrderUserResultMap() {
    // mybatis和spring整合,整合之后,交给spring管理
    SqlSession sqlSession = this.sqlSessionFactory.openSession();
    // 创建Mapper接口的动态代理对象,整合之后,交给spring管理
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

    // 使用userMapper执行根据条件查询用户,结果封装到Order类中
    List<Order> list = userMapper.queryOrderUserResultMap();
    for (Order o : list) {
        System.out.println(o);
    }
    // mybatis和spring整合,整合之后,交给spring管理
    sqlSession.close();
}

一对多

业务场景:订单用户,一个用户对应多条订单信息,此为一对多。做法如下:

1. 改造用户的pojo类:

(添加订单集合属性)

//订单类
pulic class Order{
    private int id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;
    //下面省略get和set方法
}

//用户信息类
pulic void User{
    //原用户属性
    private int id;
    private String username;
    private String address;
    //新加订单集合属性
    private List<Order> orders;
    //下面省略get和set方法
}

2. 修改mapper.xml配置文件

(使用resultMap和collection标签来实现一对多)

<!-- 因为主要查询的是user 所以先配置User类的结果 -->
<resultMap type="user" id="userOrderResultMap">
    <!-- 第一步:配置User类的对应关系 -->
    <id property="id" column="id" />
    <result property="username" column="username" />
    <result property="sex" column="sex" />
    <result property="address" column="address" />

    <!-- 第二步:配置order类的对应关系 -->
    <!-- property:填写pojo类中集合类类属性的名称 javaType:填写集合类型的名称 ofType:list中内容的类型 -->
    <collection property="orders" javaType="list" ofType="order">
        <!-- 配置主键,是关联Order的唯一标识 这里要注意oid 是因为下面select标签的sql中给order的id起了别名 叫做oid-->
        <id property="id" column="oid" />
        <result property="number" column="number" />
        <result property="createtime" column="createtime" />
        <result property="note" column="note" />
    </collection>
</resultMap>

<!-- 一对多关联,查询订单同时查询该用户下的订单 -->
<select id="queryUserOrder" resultMap="userOrderResultMap">
    SELECT a.id,a.username,a.address,a.sex,b.id oid,b.number,b.createtime,b.note from user a left join order b on a.id = b.user_id
</select>

当然也有更多一级的一对多:collection中有collection和association,这里不多介绍。

多对多

业务场景:每个老师有多个学生,每个学生又有多个老师,此为多对多。用法如下:

1. 首先涉及到三张表:学生表(student)、教师表(teacher)、学生和教师关系表(tu_teach_rel)

public class Student{
    //学生表原属性
    private String id;
    private String name;
    private int age;
    private Gender gender;
    //学生表新加属性
    private List<Teacher> teachers;
    //下面省略get和set方法
}

public class Teacher{
    //教师表原属性
    private int id;
    private String name;
    private Gender gender;
    private Subject subject;
    private String degree;
    //教师表新加属性
    private List<Student> students;
    //下面省略get和set方法
}

public class stu_teach_rel{
    //学生教师关系表
    private int id;
    private int stu_id;
    private int teach_id;
    //这里不需要加东西
    //下面省略get和set方法
}

2. mapper.xml配置文件

<mapper namespace="com.yihaomen.mybatis.dao.StudentMapper">
    <resultMap id="studentMap" type="Student">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="age" column="age" />
        <result property="gender" column="gender" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler" />
    </resultMap>
    <resultMap id="collectionMap" type="Student" extends="studentMap">
        <collection property="teachers" ofType="Teacher">
            <id property="id" column="teach_id" />
            <result property="name" column="tname"/>
            <result property="gender" column="tgender" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
            <result property="subject" column="tsubject" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
            <result property="degree" column="tdegree" javaType="string" jdbcType="VARCHAR"/>
        </collection>
    </resultMap>
    <select id="selectStudents" resultMap="collectionMap">
    SELECT
    s.id, s.name, s.gender, t.id teach_id, t.name tname, t.gender tgender, t.subject tsubject, t.degree tdegree
    FROM
    student s
    LEFT JOIN
    stu_teach_rel str
    ON
    s.id = str.stu_id
    LEFT JOIN
    teacher t
    ON
    t.id = str.teach_id
    </select>
</mapper>

总结:

一对一可以通过<association>实现,一对多和多对多通过<collection>实现。

参考:

1. https://www.cnblogs.com/kenhome/p/7764398.html

2. https://blog.csdn.net/qq_42780864/article/details/81429114

3. https://blog.csdn.net/lks1139230294/article/details/88087470

4. https://www.jb51.net/article/126584.htm

持续更新!!!

猜你喜欢

转载自www.cnblogs.com/flyinghome/p/12358212.html