<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;
}