MyBatis复习(五):获取多表关联查询结果

<select id="selectBlogMap" resultType="java.util.Map">
    select b.* , u.nick_name from t_blog b , t_user u
    where b.user_id = u.user_id
</select>
package com.cd.blog.config;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * @Author: 落叶无痕
 * @Date: 2020/5/15 16:45
 */
public class MyBatisUtils {

    /*MyBatisUtils工具类,目的是创建全局唯一的SqlSessionFactory对象*/


    //static属于类不属于对象,且全局唯一
    private static SqlSessionFactory sqlSessionFactory = null;

    //利用静态块在初始化类时初始化SqlSessionFactory
    static {
        InputStream input = null;
        try {
			// 使用字节流方式加载classpath下的mybatis-config.xml核心配置文件
            input = Resources.getResourceAsStream("mybatis-config.xml");
			// 初始化SqlSessionFactory对象,并解析mybatis-config.xml文件
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(input);
        } catch (IOException e) {
            e.printStackTrace();
            //初始化错误时,抛出ExceptionInInitializerError异常通知调用者
            throw new ExceptionInInitializerError(e);
        }
    }

	// 创建SqlSession对象(SqlSession是JDBC的扩展类,专门用于与数据库交互)
    public static SqlSession openSession(){
        return sqlSessionFactory.openSession();
    }

	// 释放一个有效的SqlSession对象
    public static void closeSession(SqlSession sqlSession){
        if(sqlSession != null){
            sqlSession.close();
        }
    }

}
package com.cd.blog.config;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;
import java.util.Map;

/**
 * @Author: 落叶无痕
 * @Date: 2020/5/17 21:42
 */
public class TestMyBatisUtils {

    @Test
    public void demo(){
        SqlSession sqlSession = null;
        try{
            sqlSession = MyBatisUtils.openSession();
            List<Map> list = sqlSession.selectList("selectBlogMap");
            for(Map map : list){
                System.out.println(map);
            }
        }catch (Exception e){
            throw e;
        }finally {
            MyBatisUtils.closeSession(sqlSession);
        }
    }

}

1. 以java.util.Map作为查询结果,返回的数据是以键值对的格式返回的,键名是表字段名,键值是表字段的值。并且java.util.Map接口默认实现类是HashMap,根据HashMap的底层是hash表,HashMap的Key是根据Key的hash值来进行排序,hash值是一个不稳定的数字,所以各字段排序的结果就会出现乱序。


2. 为保证返回结果的个字段的前后顺序一致,需要将resultType查询结果类型改为java.util.LinkedHashMap,LinkedHashMap底层是链表,在进行数据提取时,是按照我们往里插入数据时的先后顺序进行保存,因此不会像HashMap一样出现乱序现象。

<select id="selectBlogMap" resultType="java.util.LinkedHashMap">
    select b.* , u.nick_name from t_blog b , t_user u
    where b.user_id = u.user_id
</select>


总结:

  • 使用java.util.LinkedHashMap来接收数据,在我们的开发中是非常常见的。针对于多个表的关联查询,LinkedHashMap可以有效地帮助我们进行数据的扩展,使用起来非常灵活。

  • 关于javaType:

    • resultType的接收类型可以是实体类,实体类与表结构字段一致时可以自动封装数据到实体类中
    • 当resultType为Map时,查询出来的数据是无序的。
    • resultType的类型为Map / LinkedHashMap时多用于多表关联查询。

ResultMap结果集映射

1. ResultMap适用于java对象保存多表关联查询结果,可以将查询结果映射为复杂类型的java对象。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cd.blog.dao.BlogDao">

    <!--配置实体类属性与表字段的关系映射,结果集-->
    <resultMap id="blog" type="Blog">
        <!--主键字段用id配置,非主键字段用result配置 【property:实体类属性名,column:表字段名】-->
        <id column="blog_id" property="blogId"/>
        <result column="title" property="title"/>
        <result column="content" property="content"/>
        <result column="create_time" property="createTime" javaType="java.util.Date"/>
        <result column="last_edit_time" property="lastEditTime" javaType="java.util.Date"/>
        <!--关联用户的结果集,用association标签配置-->
        <!--从文章角度:文章对作者是一对一 -->
        <!--从作者角度: 作者对文章是一对多 -->
        <association column="user_id" property="user" javaType="User">
            <id column="user_id" property="userId"/>
            <result column="nick_name" property="nickName"/>
            <result column="user_Img" property="userImg"/>
        </association>
        <!--关联分类的结果集,用association标签配置-->
        <association column="type_id" property="type" javaType="Type">
            <id column="type_id" property="typeId"/>
            <result column="type_name" property="typeName"/>
        </association>
    </resultMap>
    
</mapper>

我们在获取多表关联查询结果时,一般都会涉及到多个表的字段。这个时候,普通的实体类就无法满足我们的需求了(普通实体类对象的属性都是和对应表的字段一一对应的),当然我们也可以在实体类的基础上进行扩展。
例如:

public class Blog {

    /*自增id*/
    private Integer blogId;
    /*文章标题*/
    private String title;
    /*文章内容*/
    private String content;
    /*文章标识: 原创、转载、翻译*/
    private String flag;
    /*浏览次数*/
    private int views;
    /*最近更新时间*/
    private Date lastEditTime;

//下面这些属性用来在mybatis中进行关联查询
    /*作者:多对一关系*/
    private User user;
    /*分类:多对一关系*/
    private Type type;
}
<!--配置实体类属性与表字段的关系映射,结果集-->
<resultMap id="blog" type="Blog">
    <!--主键字段用id配置,非主键字段用result配置 【property:实体类属性名,column:表字段名】-->
    <id column="blog_id" property="blogId"/>
    <result column="title" property="title"/>
    <result column="content" property="content"/>
    <result column="flag" property="flag"/>
    <result column="views" property="views"/>
    <result column="last_edit_time" property="lastEditTime" javaType="java.util.Date"/>
    <!--关联用户的结果集,用association标签配置-->
    <!--从文章角度:文章对作者是一对一 -->
    <!--从作者角度: 作者对文章是一对多 -->
    <association column="user_id" property="user" javaType="User">
        <id column="user_id" property="userId"/>
        <result column="nick_name" property="nickName"/>
        <result column="user_Img" property="userImg"/>
    </association>
    <!--关联分类的结果集,用association标签配置-->
    <association column="type_id" property="type" javaType="Type">
        <id column="type_id" property="typeId"/>
        <result column="type_name" property="typeName"/>
    </association>
</resultMap>


dto(Data Transfer Object)是一个特殊的java bean,名为:数据传输对象。dto对象是对原始对象的扩展,用于数据的保存和传递。


前面提到,在保存和传输多表关联查询结果时,可以修改普通实体类进行扩展。平时开发的时候,很多程序员都是这么干的,包括我在内。但严格来讲,这是代码不规范的,因为实体类和表字段的一一对应的,表中有多少个字段,对应的实体类就有多少个属性。

此时,我们就可以通过dto数据传输对象来达到目的
例如:

public class BlogDTO {
	//文章
	private Blog blog;
    //作者
    private User user;
    //分类
    private Type type;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章