MyBatis框架核心之(四)Mapper文件使用resultMap及多表查询

2018-02-27 11:52:54来源:oschina作者:bugwfq人点击

分享
四、resultMap与多表查询(mapper.xml文件)
一、resultMap简介

MyBatis是基于“数据库结构不可控”的思想建立的,也就是我们希望数据库遵循第三范式或BCNF,但实际事与愿违,那么结果集映射就是MyBatis为我们提供这种理想与现实间转换的手段了,而resultMap就是结果集映射的配置标签了。

1.从SQL查询结果到领域模型实体                  


在深入ResultMap标签前,我们需要了解从SQL查询结果集到JavaBean或POJO实体的过程。


1. 通过JDBC查询得到ResultSet对象


2. 遍历ResultSet对象并将每行数据暂存到HashMap实例中,以结果集的字段名或字段别名为键,以字段值为值


3. 根据ResultMap标签的type属性通过反射实例化领域模型


4. 根据ResultMap标签的type属性和id、result等标签信息将HashMap中的键值对,填充到领域模型实例中并返回

2.使用场景


在项目的实际开发中,有可能会遇到这样两种情况。


1. 实体类中的属性名与列名不相同,不能改但。导致不能自动装配值


2. 多表查询的返回值中可能需要其他对象,或者数组(一对一和一对多)

二、resultMap标签解释
标签及属性介绍

标签:


id属性,resultMap标签的标识。


type属性,返回值的全限定类名,或类型别名。


autoMapping属性,值范围true(默认值)|false, 设置是否启动自动映射功能,自动映射功能就是自动查找与字段名小写同名的属性名,并调用setter方法。而设置为false后,则需要在`resultMap`内明确注明映射关系才会调用对应的setter方法。


可以设置的子标签映射:


1).id标签 :ID 结果,将结果集标记为ID,以方便全局调用(适用于指定主键)


column 数据库的列名


Property需要装配的属性名


2).result标签:将查询到的列的值,反射到指定的JavaBean的 属性上


column 数据库的列名


Property 需要装配的属性名


3).association标签:复杂类型 , 多表查询(一对一)时,将根据外键或某列信息查询出的对象,直接装配给某个resultMap指定的属性。


column 数据库的列名


Property 需要装配的属性名


select 指定用来多表查询的sqlmapper

4).Collection标签:复杂类型,多表查询(一对多),将查询出的结果集合直接装配给某个对应的集合


column 数据库的列名


Property 需要装配的属性名


javaType指定用什么类型接受返回的值(必要)


select 指定用来多表查询的sqlmapper


5).constructor– 用来将结果反射给一个实例化好的类的构造器


a)idArg –ID 参数;将结果集标记为ID,以方便全局调用 b)arg –反射到构造器的通常结果


6).discriminator – 使用一个结果值以决定使用哪个resultMap


a)case – 基本一些值的结果映射的case 情形


i.nestedresult mappings –一个case 情形本身就是一个结果映射,因此也可以包括一些相同的元素,也可以引用一个外部resultMap。



<resultMap type="" id="">

""property=""/>

""property=""/>

"" column="" select="">

"" column="" javaType="" select="">




三、各标签使用

1.id、result


id、result是最简单的映射,id为主键映射;result其他基本数据库表字段到实体类属性的映射。



实体字段 表的列名

sid stuid

sname stuname

gid gid

grade grade




"student" id="studentMap" autoMapping="true">

"stuid"property="sid"/>

"stuname" property="sname"/>




id、result语句属性配置细节:


属性


描述



property


需要映射到JavaBean的属性名称。



column


数据表的列名或者标签别名。



javaType


一个完整的类名,或者是一个类型别名。如果你匹配的是一个JavaBean,那MyBatis通常会自行检测到。然后,如果你是要映射到一个HashMap,那你需要指定javaType要达到的目的。



jdbcType


数据表支持的类型列表。这个属性只在insert,update或delete的时候针对允许空的列有用。JDBC需要这项,但MyBatis不需要。如果你是直接针对JDBC编码,且有允许空的列,而你要指定这项。



typeHandler


使用这个属性可以覆写类型处理器。这项值可以是一个完整的类名,也可以是一个类型别名。



支持的JDBC类型为了将来的引用,MyBatis支持下列JDBC 类型,通过JdbcType 枚举: BIT,FLOAT,CHAR,TIMESTAMP,OTHER,UNDEFINED,TINYINT,REAL,VARCHAR,BINARY,BLOB,NVARCHAR,SMALLINT,DOUBLE,LONGVARCHAR,VARBINARY,CLOB,NCHAR,INTEGER,NUMERIC,DATE,LONGVARBINARY,BOOLEAN,NCLOB,BIGINT,DECIMAL,TIME,NULL,CURSOR

2.association联合


联合元素用来处理“一对一”的关系。


需要指定映射的Java实体类的属性,属性的javaType(通常MyBatis 自己会识别)。对应的数据库表的列名称。如果想覆写的话返回结果的值,需要指定typeHandler。 不同情况需要告诉MyBatis 如何加载一个联合。MyBatis 可以用两种方式加载:


1.select: 执行一个其它映射的SQL 语句返回一个Java实体类型。较灵活; 2.resultsMap: 使用一个嵌套的结果映射来处理通过join查询结果集,映射成Java实体类型。

association 标签


property=多表查询装配的属性名


column=通过那一列关联


select=指定查询语句,如果查询语句在其他的namespace中,则需要写全namespace.方法id

例如:在获取某个学生的信息的同时又想获取所属班级的所有信息



学生实体中的字段




package cn.et.fuqiang.resultMap.entity;

publicclass Student {

privateInteger sid;//学生id

private Stringsname; //学生姓名

privateInteger gid; //班级id

private Gradegrade; //所属班级的所有信息

}




班级实体的字段




package cn.et.fuqiang.resultMap.entity;

import java.util.List;

publicclass Grade {

private Integerid;//班级id

private Stringgname;//班级名称

public Grade() {

super();

// TODO Auto-generated constructor stub

}

}




在Student的字段中,Grade班级实体,需要查询班级表才能获取,学生表中没有该列(所以需要使用多表查询中的 association标签)


想要使用多表查询先要定义一个resultMap,简单来说其实相当于一个工厂,可以指定某个实体中那些属性可以装哪一列的值,并且还要定义类似于子查询的方法。



"student"id="gradeInStudent">

"stuid"property="sid"/>

"stuname" property="sname"/>

"grade" column="gid" select="cn.et.fuqiang.resultMap.xml.GradeXmlInterface.queryGradeById">




在namespace="cn.et.fuqiang.resultMap.xml.GradeXmlInterface下的方法






在这个resultMap中


type:是上面定义的学生类(使用了别名,如果没有别名可以写全类名)


id:是这个resultMap的标识


因为表中的字段与实体中的不同,所以使用了下面两个子标签,将表的列与实体的属性做了映射。这样才能将表中的值获取到实体的属性中。



"stuid"property="sid"/>




"stuname"property="sname"/>


因为实体中还要一个班级实体,但表中没有该字段,所以就要用多表查询



"grade"column="gid" select="cn.et.fuqiang.resultMap.xml.GradeXmlInterface.queryGradeById">


(这里的property是实体中的字段,而column=gid就相当于关联的条件了


而select就是该关联条件对应的查询方法)

主sql


在这里我们使用resultMap定义返回的类型,这样就会自动将所有内容,装到对应的属性上


然后直接使用该主sql,查询,获取的值就会自动对应到其中。



以上代码写为标准的sql语句


select s.*,g.*from student s inner join grade g ons.gid=g.gid


3. collection聚集

聚集元素用来处理“一对多”的关系。需要指定映射的Java实体类的属性,属性的javaType(一般为ArrayList);列表中对象的类型ofType(Java实体类);对应的数据库表的列名称; 不同情况需要告诉MyBatis 如何加载一个聚集。MyBatis 可以用两种方式加载:


1.select:执行一个其它映射的SQL 语句返回一个Java实体类型。较灵活; 2.resultsMap: 使用一个嵌套的结果映射来处理通过join查询结果集,映射成Java实体类型。

Collection标签


property=多表查询装配的属性名


column=通过那一列关联


select=指定查询语句,如果查询语句在其他的namespace中,则需要写全namespace.方法id


javaType=java实体中接受的集合类型

例如,一个班级有多个学生。


学生实体中的字段




package cn.et.fuqiang.resultMap.entity;

publicclass Student {

privateInteger sid;//学生id

private Stringsname; //学生姓名

privateInteger gid; //班级id

}




班级实体的字段




package cn.et.fuqiang.resultMap.entity;

import java.util.List;

publicclass Grade {

private Integerid;//班级id

private String gname;//班级名称

private List students;//该班级下所有的学生

public Grade() {

super();

// TODO Auto-generated constructor stub

}

}



在Grade实体中有个List students属性,需要查询学生表才能获取,班级表中没有该信息(所以要使用collection聚集查询对应的结果集)


"grade" id="studentsInGrade">

"gid" property="id" />

"students" column="gid" javaType="list" select="cn.et.fuqiang.resultMap.xml.StudentXmlInterface.quserUserByGid">




在namespace="cn.et.fuqiang.resultMap.xml.StudentXmlInterface"下的查询语句和类型




"student" id="studentMap" autoMapping="true">

"stuid" property="sid"/>

"stuname" property="sname"/>







注意:因为实例中学生的字段名与表中的不同所以,又加了一个学生查询专属的resultMap



在这个resultMap中


type:是上面定义的学生类(使用了别名,如果没有别名可以写全类名)


id:是这个resultMap的标识


因为表中的字段与实体中的不同,所以使用了下面的子标签,将表的列与实体的属性做了映射。这样才能将表中的值获取到实体的属性中。



"gid"property="id"/>


使用多表查询获取某个班级下的所有学生



"students" column="gid"javaType="list" select="cn.et.fuqiang.resultMap.xml.StudentXmlInterface.quserUserByGid">



(这里的property是实体中的字段,而column=gid就相当于关联的条件了


而select就是该关联条件对应的查询方法)


主sql



"queryAllGrade"resultMap="studentsInGrade">

select * from grade



执行该映射时就会自动根据resultMap自动调用其中内嵌的sql语句查询所有学生


所有代码实例


Mybatis配置



mybatis.xml




<?xmlversion="1.0"encoding="UTF-8"?>

"cn/et/fuqiang/resultMap/jdbc.properties">

"cn.et.fuqiang.resultMap.entity"/>

"development">

"development">

"JDBC" />

"POOLED">

"driver" value="${driverClass}" />

"url" value="${url}" />

"username" value="${user}" />

"password" value="${password}" />

"cn.et.fuqiang.resultMap.xml.StudentXmlInterface"/>

"cn.et.fuqiang.resultMap.xml.GradeXmlInterface"/>



Jdbc连接四要素配置



jdbc.properties




url=jdbc:oracle:thin:@localhost :1521:orcl

user=mybatis

password=mybatis

driverClass=oracle.jdbc.OracleDriver



两个实体



student实体




package cn.et.fuqiang.resultMap.entity;

publicclass Student {

private Integersid;//学生id

private Stringsname;//学生姓名

private Integergid;//班级id

private Gradegrade;//所属班级的所有信息

public Student() {

super();

// TODO Auto-generated constructor stub

}

public Student(Integer sid, String sname, Integer gid, Grade grade) {

super();

this.sid = sid;

this.sname = sname;

this.gid = gid;

this.grade = grade;

}

public Integer getSid() {

returnsid;

}

publicvoid setSid(Integer sid) {

this.sid = sid;

}

public String getSname() {

returnsname;

}

publicvoid setSname(String sname) {

this.sname = sname;

}

public Integer getGid() {

returngid;

}

publicvoid setGid(Integer gid) {

this.gid = gid;

}

public Grade getGrade() {

returngrade;

}

publicvoid setGrade(Grade grade) {

this.grade = grade;

}

}




Grade实体




package cn.et.fuqiang.resultMap.entity;

import java.util.List;

publicclass Grade {

private Integerid;//班级

private Stringgname;//班级名称

private Liststudents;//该班级下所有的学生

public Grade() {

super();

// TODO Auto-generated constructor stub

}

public Grade(Integerid, String gname) {

super();

this.id = id;

this.gname = gname;

}

public String getGname() {

returngname;

}

publicvoid setGname(String gname) {

this.gname = gname;

}

public Integer getId() {

returnid;

}

publicvoid setId(Integer id) {

this.id = id;

}

public List getStudents() {

returnstudents;

}

publicvoid setStudents(List students) {

this.students = students;

}

}




两个接口映射的接口



GradeXmlInterface.java




package cn.et.fuqiang.resultMap.xml;

import java.util.List;

import cn.et.fuqiang.resultMap.entity.Grade;

publicinterface GradeXmlInterface {

public Grade queryGradeById(Integer id);

public List queryAllGrade();

}




StudentXmlInterface.java




package cn.et.fuqiang.resultMap.xml;

import java.util.List;

import cn.et.fuqiang.resultMap.entity.Student;

publicinterface StudentXmlInterface {

public Student queryStudentById(Integer sid);

public List quserAllStudent();

public List quserUserByGid();

}




两个映射的mapper.xml



GradeXmlInterface.xml




<?xmlversion="1.0"encoding="UTF-8"?>

"cn.et.fuqiang.resultMap.xml.GradeXmlInterface">

"grade" id="gradeMap" autoMapping="false">

"gid"property="id"/>

"gname" property="gname"/>

"grade" id="studentsInGrade">

"gid"property="id"/>

"students" column="gid" javaType="list" select="cn.et.fuqiang.resultMap.xml.StudentXmlInterface.quserUserByGid">




StudentXmlInterface.xml




<?xmlversion="1.0"encoding="UTF-8"?>

"cn.et.fuqiang.resultMap.xml.StudentXmlInterface">

"student" id="studentMap" autoMapping="true">

"stuid"property="sid"/>

"stuname" property="sname"/>

"student" id="gradeInStudent">

"stuid"property="sid"/>

"stuname" property="sname"/>

"grade" column="gid" select="cn.et.fuqiang.resultMap.xml.GradeXmlInterface.queryGradeById">



测试类


package cn.et.fuqiang.resultMap.xml;

import java.io.InputStream;


import java.util.List;

import org.apache.ibatis.session.SqlSession;


import org.apache.ibatis.session.SqlSessionFactory;


import org.apache.ibatis.session.SqlSessionFactoryBuilder;


import org.junit.Test;

import cn.et.fuqiang.resultMap.entity.Grade;


import cn.et.fuqiang.resultMap.entity.Student;


public class ResultMapXmlTest {


private static SqlSession session;


private static GradeXmlInterface gradeInter=null;


private static StudentXmlInterface studentInter=null;


static{


//mybatis的配置文件


String resource ="mybatis.xml";


//使用类加载器加载mybatis的配置文件(它也加载关联的映射文件)


InputStream is =GradeXmlInterface.class.getResourceAsStream(resource);


//构建sqlSession的工厂


SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);


//使用MyBatis提供的Resources类加载mybatis的配置文件(它也加载关联的映射文件)


//Readerreader = Resources.getResourceAsReader(resource);


//构建sqlSession的工厂


//SqlSessionFactorysessionFactory = new SqlSessionFactoryBuilder().build(reader);


//创建能执行映射文件中sql的sqlSession


session = sessionFactory.openSession();


gradeInter=session.getMapper(GradeXmlInterface.class);


studentInter=session.getMapper(StudentXmlInterface.class);


}


//@Test


public void queryGradeTest(){


Grade grade=gradeInter.queryGradeById(1);


System.out.println(grade.getId()+"------"+grade.getGname());


}


//@Test


public void queryStudentTest(){


Student student=studentInter.queryStudentById(1);


System.out.println(student.getSid()+"------"+student.getSname());


}


//@Test


public void queryGradeInStudent(){


List students=studentInter.quserAllStudent();


for (Student stu : students) {


System.out.println(stu.getSid()+"------"+stu.getSname()+"-------"+stu.getGrade().getGname());


}

}


@Test


public void queryStudentInGrade(){


List students=gradeInter.queryAllGrade();


for (Grade grade : students) {


System.out.println(grade.getGname()+"班"+grade.getStudents().size()+"人");


}


}


}


最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台