zoukankan      html  css  js  c++  java
  • 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

    持续更新!!!

  • 相关阅读:
    线程池和进程池
    初识数据库
    线程q
    event事件
    死锁和递归锁
    信号量
    PythonStudy——线程中的几种消息队列
    PythonStudy——GIL Global Interpreter Lock 全局解释器锁
    PythonStudy——异步回调
    PythonStudy——日志模块 logging
  • 原文地址:https://www.cnblogs.com/flyinghome/p/12358212.html
Copyright © 2011-2022 走看看