mybatis处理返回结果集

结果处理

1 简单类型输出映射

返回简单基本类型

//查询管理员总数
int adminCount();
<select id="adminCount" resultType="int">
        select count(*) from admin
</select>
  • 返回结果需要定义后才能使用简称

    • eg:resultType="Admin" 已经定义过别名了,所以就可以使用简称

    • 那么java中其它常用类型简称如何使用?(不使用简称就需要用全类名,eg:java.util.List)

      • 在mybatis底层源码中定义了一些常用的类型的简称

794769acd7964b44bb646cee0d315342.png

dc81f836aa394b8faec49d21ea023cca.png

dc987f4058494cfc935327cdc9978b91.png

  • 也可以在官网中查看定义好的类型简称或者自己可以重写已有的类型处理器或创建自己的类型处理器来处理不支持的或非标准的类型,具体参考mybatis – MyBatis 3 | 配置

2 对象映射

  • mybatis会将查询到的结果自动封装到一个对象中,会自己创建给定类型的类的对象(通过是否执行无参构造方法我们可以看到)

  • 自动封装的条件:

    • 开启了全局的自动结果映射,PARTIAL默认是单张表开启的a940773f98644fdea54f5730f0e1c5ee.png

    • 数据库列名与属性名名字相同,mybatis会自动将查询结果封装到pojo对象中;如果不一样,比如java中使用标准驼峰命名,数据库中使用下划线连接命名,这个时候可以通过开启驼峰命名自动映射或开启全局设置实现自动转换98bd7ae4827b4f609913b89495bd4780.png

例如: 

定义的类中的属性名:

a79aa7fbe9c545aeb913a61e3ec3cfef.png

 <select id="findAdminById" parameterType="int" resultType="Admin">
      // 定义别名acc、adminGender
      select id,account acc,password,admin_gender adminGender from admin where id =#{id};
</select>

可以看到列名与属性名相同的,mybatis会自动将结果封装到pojo对象中,不同的则不会映射:

32e32ea526034a3b813b33668fa1a70e.png

开启驼峰命名自动映射后即使不设置别名,也可以自动实现驼峰映射(eg:admin_gender ---> adminGender)

  • 在全局配置文件中开启

c2eb7579d4114a9a937ca2f97135d180.png

查询多行数据,也就是返回多个对象

  • mybatis会自动创建多个对象,并通过set方法为属性赋值,然后将这些对象自动的封装到List集合中

List<Admin> findAdmins();
<select id="findAdmins" resultType="Admin">
    select id,account,password,admin_gender from admin
</select>

420e8f96e86c48f294092cc8121f0023.png

3 特殊处理定义 resultMap

定义 resutlMap

  • 在resutlMap 标签中,我们可以自定义结果映射

<resultMap id="adminMap" type="Admin">
     <id column="id" property="id"></id><!-- 封装映射主键列 -->
     <result column="account" property="account"></result>
     <result column="password" property="password"></result>
     <result column="admin_gender" property="gender"></result> 
</resultMap> 

  (1) resutlMap 的 id 属性是 resutlMap 的唯一标识,本例中定义为“adminMap”

  (2) resutlMap 的 id 属性是映射的 POJO 类

  (3) id 标签映射主键,result 标签映射非主键

  (4) property 设置 POJO 的属性名,column 数据库中列名

使用 resutlMap

<select id="findAdmins" resultMap="adminMap">
      select id,account,password,admin_gender from admin
</select>

  (1) 本例的输出映射使用的是 resultMap,而非 resultType

  (2) resultMap 引用了 adminMap

在说关联查询之前我们先说一个问题:

在关联查询的时候我们需要同时获取几张表中的数据,在模型类中进行封装的时候,我们会在一个类中把其他类中已有的属性再定义一遍,比如以前我们会在Student类会中再定义一遍我们需要的Dorm类中已有的属性,这样显然是不合理的,所以我们现在直接在Student中关联Dorm类中的属性,它就会将数据封装到关联的类中去,以减少代码冗余。

eg:

2e38bbf643a84d3e97a7cdda6d33a57f.png

4 多表关联处理结果集及嵌套查询

4.1 多表关联处理结果

resultMap 元素中 association , collection 元素.

  • association :是一对一使用的,用来封装类中所关联的对象信息,会创建一个关联对象

    • property="类中的属性名" ,javaType="类型",select表示要执行的sql语句

  • collection:关联元素处理一对多关联

4.2 嵌套查询

  • 将一个多表关联查询拆分为多次查询,查询主表数据,然后查询关联表数据

<association property="dorm" column="dormid" 
             select="findDormById" javaType="Dorm">
</association>

  (1) select:指定关联查询对象的 Mapper Statement ID 为 findDormById

  (2) column="dormid" :关联查询时将 dormid 列的值传入 findDormById,传多个参数的话就是{"属性名"="参数","属性名"="参数"}

  (3) collection 和 association 都需要配置 select 和 column 属性,两者配置方法相同

案例数据库表:

student表:

8542ef62adff4a6892ca94fa5e9d5626.png

 dorm表:

ddfcb4959c9840348e33da99ec6cc0e7.png

 admin表:

592628e55fe54ef08e1a5207b5f4ca9a.png

案例一

  • 在查询学生信息的时候将宿舍号和操作人也查询出来,这时就要用到多表关联结果处理

方法一:通过三张表关联查询,一次把信息都查询出来,在封装信息的时候再处理

Student findStudentById(int id);
<resultMap id="studentMap" type="com.ffyc.mybatispro.model.Student">
    <!--  
         mybatis默认配置,一旦出现了嵌套关联查询,就把自动映射关闭了,所以这里我们需要自定义结果映射
         要想让它继续自动映射,就需要在全局配置文件中设置autoMappingBehavior属性值为true,
         我们是不建议在多表查询时开启的,因为这需要高度规范的命名
    -->
    <id column="id" property="id"></id>
    <result column="num" property="num"></result>
    <result column="name" property="name"></result>
    <result column="gender" property="gender"></result>
    <result column="birthday" property="birthday"></result>
    <result column="oper_time" property="operTime"></result>
    <!--
      association:用来封装关联的对象信息
      property="dorm", 就是创建一个关联的对象
    -->
    <association property="dorm" javaType="Dorm">
        <!--
            这里的column是数据库中的列名或者我们定义的列的别名 
            property是Dorm类中的属性
        -->
        <result column="dormNum" property="num"></result>
    </association>
    <association property="admin" javaType="Admin">
        <result column="account" property="account"></result>
    </association>
</resultMap>
<select id="findStudentById" parameterType="int" resultMap="studentMap">
    SELECT 
        s.id,
        s.num,
        s.name,
        s.gender,
        s.birthday,
        d.num dormNum,
        a.account,
        s.oper_time
    FROM student s
              LEFT JOIN dorm d ON s.dormid = d.id
              LEFT JOIN admin a ON s.adminid = a.id
              WHERE s.id = #{id}
</select>

测试:

@Test
public void find() {
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    
    Student student = studentDao.findStudentById(1);
    
    sqlSession.commit();
    sqlSession.close();
}

c98d4c824a6b4410869d4076354dd5cf.png

  • 在这里还要补充一点:如果在拿到学生信息后,需要获取学生的宿舍号,首先要拿到学生对象中的Dorm对象,然后再获取Dorm对象中属性

    System.out.println(student.getDorm().getNum());
    • 前端也一样30fbc45db6de43528ec4d4cc69db3538.png

  • 注意:查询多个学生信息只需要将sq语句中的WHERE s.id = #{id}这个条件给去掉,resultMap和查询一个是一样的

    List<Student> findStudents();

方法二:嵌套查询(把sql分成多次查询,先查询学生信息,再通过外键查询宿舍和操作人信息)

<resultMap id="studentMap" type="Student">
    <id column="id" property="id"></id>
    <result column="num" property="num"></result>
    <result column="name" property="name"></result>
    <result column="gender" property="gender"></result>
    <result column="birthday" property="birthday"></result>
    <result column="oper_time" property="operTime"></result>
    <!--
        select="findDormById" 查询语句id
        column="dormid" 将查询到的dormid作为条件再查询
        javaType="Dorm" 类型
    -->
    <association property="dorm" column="dormid" 
                 select="findDormById" javaType="Dorm"></association>
    <association property="admin" column="adminid" 
                 select="findAdminById" javaType="Admin"></association>
</resultMap>
<select id="findStudentById" resultType="Student" resultMap="studentMap">
     select id,num,name,gender,birthday,dormid,adminid from student where id = #{id}
</select>
<select id="findDormById" resultType="Dorm">
     select num from dorm where id = #{dormid}
</select>
<select id="findAdminById" resultType="Admin">
    select account from admin where id = #{adminid}
</select>

测试:

ccabeb07c9434f6fa69b7f4443aa619c.png

案例二

  • 在查询宿舍的同时查询出这个宿舍中所住学生的信息

方法1:关联查询

类中属性定义:

e231d6403c804109942461ddc89e9407.png

 Dorm findDormById(int id);
<resultMap id="dormMap" type="Dorm">
    <id column="id" property="id"></id>
    <result column="num" property="num"></result>
    <association property="admin" javaType="Admin">
        <result column="account" property="account"></result>
    </association>
    <!--
        property="students" 属性
        javaType="list" students的类型(list为类型简称)
        ofType="Student" 集合里所装数据的类型
    -->
    <collection property="students" javaType="list" ofType="Student">
        <result column="snum" property="num"></result>
        <result column="name" property="name"></result>
    </collection>
</resultMap>
<select id="findDormById" resultMap="dormMap" resultType="Dorm">
        SELECT
            d.id,
            d.num,
            s.num,
            s.name,
            a.account
       FROM dorm d
       LEFT JOIN admin a ON d.adminid = a.id
       LEFT JOIN student s ON d.id = s.dormid
                  WHERE d.id = 1
</select>

测试:

@Test
public void find(){
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    DormDao dormDao = sqlSession.getMapper(DormDao.class);
    //通过id查询宿舍和这个宿舍中所住学生的信息
    Dorm dorm = dormDao.findDormById(1);
    sqlSession.close();
}

3fe786f7017d4affad6e0cebc3f3b0fd.png

方法2:嵌套查询

<resultMap id="dormMap2" type="Dorm">
    <id column="id" property="id"></id>
    <result column="num" property="num"></result>
    <association property="admin" column="adminid" javaType="Admin"  select="findAdminById1"></association>
    <collection property="students" javaType="list" ofType="Student" column="id"
                select="findStudents1"></collection>
</resultMap>
<select id="findDormById1" resultMap="dormMap2" resultType="Dorm">
      SELECT id,num,adminid FROM dorm WHERE id = #{id}
</select>
<select id="findAdminById1" resultType="Admin">
    SELECT account FROM admin WHERE id = #{adminid}
</select>
<select id="findStudents1" resultType="Student">
    SELECT num,NAME FROM student WHERE dormid = #{id}
</select>

测试:

4aa9e887bd7447c88cdf83724902a591.png

  • 查询所有的宿舍及关联的学生信息

方法1:关联查询

List<Dorm> findDorms();
<select id="findDorms" resultMap="dormMap">
     SELECT
            d.id,
            d.num,
            s.num,
            s.name,
            a.account
       FROM dorm d
       LEFT JOIN admin a ON d.adminid = a.id
       LEFT JOIN student s ON d.id = s.dormid
</select>

测试:

@Test
public void find(){
    SqlSession sqlSession = MybatisUtil.getSqlSession();
    DormDao dormDao = sqlSession.getMapper(DormDao.class);
    //查询每个宿舍,并关联每个宿舍中有多少个学生
    List<Dorm> dorms = dormDao.findDorms();
    /*
      对查询结果进行获取输出
     */
    // 遍历所有宿舍
    for (Dorm dorm:dorms){
        System.out.println(dorm);
        // 获取到宿舍中所有学生信息
        for (Student student:dorm.getStudents()){
            System.out.println(student.getNum()+":"+student.getName());
        }
    }
    sqlSession.close();
}

可以看到查询出了所有的宿舍以及宿舍所住学生的信息:

2c07788c7ef44cceb651d6a8efafeb47.png

方法2:嵌套查询

<resultMap id="dormMap" type="Dorm">
    <id column="id" property="id"></id>
    <result column="num" property="num"></result>
    <association property="admin" column="adminid" javaType="Admin" select="findAdminById"></association>
    <collection property="students" javaType="list" ofType="Student" column="id"
                select="findStudents"></collection>
</resultMap>
<select id="findDorms" resultType="Dorm" resultMap="dormMap">
    SELECT id,num,adminid FROM dorm
</select>
<select id="findAdminById" resultType="Admin">
    SELECT account FROM admin WHERE id = #{adminid}
</select>
<select id="findStudents" resultType="Student">
    SELECT num,NAME FROM student WHERE dormid = #{id}
</select>

测试:806ac0c3e5de483b845b73056249e1fb.png