使用Mybatis实现关联查询,分为一对一和一对多两种情况,最后并对ResultMap进行一个简要说明。
创建表和数据
创建教师表,班级表,学生表,
假设一个老师只负责教一个班,那么老师和班级之间的关系是一对一的关系。
假设一个班级有多个学生,那么班级和学生之间的关系是一对多的关系。
CREATE TABLE teacher(
t_id number(5) PRIMARY KEY,
t_name VARCHAR2(20)
);
CREATE TABLE class(
c_id number(5) PRIMARY KEY ,
c_name VARCHAR2(20),
teacher_id number(5) references teacher(t_id)
);
--创建序列
create sequence teacher_seq;
create sequence class_seq;
INSERT INTO teacher VALUES(teacher_seq.nextval,'mike');
INSERT INTO teacher VALUES(teacher_seq.nextval,'john');
INSERT INTO class VALUES(class_seq.nextval,'Java10', 1);
INSERT INTO class VALUES(class_seq.nextval,'Java11', 2);
commit;
select * from teacher;
select *from class;
select * from teacher t,class s where t.t_id = s.teacher_id and s.c_id=1
--学生表
CREATE TABLE student(
s_id number(5) PRIMARY KEY ,
s_name VARCHAR2(20),
class_id number(5)
);
create sequence student_seq;--序列
--FK
alter table student add constraint fk_cid foreign key(class_id) references class(c_id)
INSERT INTO student VALUES(student_seq.nextval,'zhangsan', 1);
INSERT INTO student VALUES(student_seq.nextval,'wangwu', 1);
INSERT INTO student VALUES(student_seq.nextval,'liufei', 1);
INSERT INTO student VALUES(student_seq.nextval,'cuihua', 2);
INSERT INTO student VALUES(student_seq.nextval,'zhangfei', 2);
INSERT INTO student VALUES(student_seq.nextval,'xionger', 2);
select * from student;
--查询某一个班级的老师,学生信息
SELECT * FROM class c, teacher t,student s where c.c_id = s.class_id and t.t_id=c.teacher_id and c.c_id=1
一、一对一关联
(1)、定义实体类
package com.hlx.entity;
import java.util.List;
/**
* Classes 班级表
*
* 一个班级有多个学生
*
* @author Administrator
*
*/
public class Classes {
private int id; // c_id
private String name; // c_name
/**
* class表中有一个teacher_id字段,所以在Classes类中定义一个teacher属性,
* 用于维护teacher和class之间的一对一关系,通过这个teacher属性就可以知道这个班级是由哪个老师负责的
*/
private Teacher teacher;//
//使用一个List<Student>集合属性表示班级拥有的学生
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
public Classes(int id, String name, Teacher teacher) {
super();
this.id = id;
this.name = name;
this.teacher = teacher;
}
public Classes(int id) {
super();
this.id = id;
}
public Classes() {
super();
}
@Override
public String toString() {
return "Classes [id=" + id + ", name=" + name + ", teacher=" + teacher
+ "]";
}
}
package com.hlx.entity;
/**
* teachar 老师类
* @author Administrator
*
*/
public class Teacher {
private int id; // t_id
private String name; // t_name
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher(int id, String name) {
super();
this.id = id;
this.name = name;
}
public Teacher(int id) {
super();
this.id = id;
}
@Override
public String toString() {
return "Teacher [id=" + id + ", name=" + name + "]";
}
public Teacher() {
super();
}
}
(2)定义sql映射文件ClassesMapper.xml
<?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.hlx.mapping.ClassesMapper">
<!-- 根据班级id查询班级信息(带老师的信息)
##1. 联表查询: select * from teacher t,class s where t.t_id = s.teacher_id and s.c_id=1
-->
<select id="getClass" parameterType="int" resultMap="classMap">
select * from class s, teacher t where t.t_id = s.teacher_id and s.c_id=#{id}
</select>
<!-- 使用resultMap映射实体类和字段之间的一一对应关系 type:实体类类型; id:名称-->
<resultMap type="com.hlx.entity.Classes" id="classMap">
<id property="id" column="c_id"/> <!-- pk -->
<result property="name" column="c_name"/> <!-- column -->
<!-- association 关联老师类-->
<association property="teacher" javaType="com.hlx.entity.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
</resultMap>
<!-- ##2 执行两次查询
SELECT * FROM class WHERE c_id=1; //teacher_id=1
SELECT * FROM teacher WHERE t_id=1;//使用上面得到的teacher_id
-->
<select id="getClass2" parameterType="int" resultMap="ClassMap2">
select * from class where c_id=#{id}
</select>
<!--(2)使用resultMap映射实体类和字段之间的一一对应关系 -->
<resultMap type="com.hlx.entity.Classes" id="ClassMap2">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<!-- teacher关联字段 -->
<association property="teacher" column="teacher_id" select="getTeacher"/>
</resultMap>
<!--(3)老师的sql语句 ;必须对应相应的字段 -->
<select id="getTeacher" parameterType="int" resultType="Teacher">
select t_id id,t_name name from teacher where t_id=#{id}
</select>
</mapper>
<!-- 将mapper文件加入到配置文件中 -->
<mappers>
<mapper resource="com/hlx/mapping/ClassesMapper.xml"/>
</mappers>
(3)测试类
package com.hlx.test;
import java.io.InputStream;
import java.util.List;
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 org.apache.log4j.Logger;
import org.junit.Test;
import com.hlx.entity.Classes;
import com.hlx.util.MyBatisUtil;
/**
* 测试类
*s
*
* @author Administrator
*
*/
public class ClassesTest {
// 日志对象
private Logger logger = Logger.getLogger(ClassesTest.class);
/**
* Classes [id=2, name=Java11, teacher=Teacher [id=2, name=john]]
*/
@Test
public void getId() {
SqlSession session = null;
try {
// 获得会话
session = MyBatisUtil.getSqlSession(true);
// 映射sql的标识字符串
String statement = "com.hlx.mapping.ClassesMapper.getClass";
// 执行插入操作
Classes userinfos = session.selectOne(statement, 2);
logger.debug("查询数据!");
System.out.println(userinfos);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
session.close(); // 对应一次数据库会话,会话结束必须关闭
}
}
/**
* Classes [id=1, name=Java10, teacher=Teacher [id=1, name=mike]]
*/
@Test
public void getId2() {
SqlSession session = null;
try {
// 获得会话
session = MyBatisUtil.getSqlSession(true);
// 映射sql的标识字符串
String statement = "com.hlx.mapping.ClassesMapper.getClass2";
// 执行插入操作
Classes userinfos = session.selectOne(statement, 1);
logger.debug("查询数据!");
System.out.println(userinfos);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
session.close(); // 对应一次数据库会话,会话结束必须关闭
}
}
}
二、一对多关联
(1)、定义实体类
package com.hlx.entity;
import java.util.List;
/**
* Classes 班级表
*
* 一个班级有多个学生
*
* @author Administrator
*
*/
public class Classes {
private int id; // c_id
private String name; // c_name
/**
* class表中有一个teacher_id字段,所以在Classes类中定义一个teacher属性,
* 用于维护teacher和class之间的一对一关系,通过这个teacher属性就可以知道这个班级是由哪个老师负责的
*/
private Teacher teacher;//
//使用一个List<Student>集合属性表示班级拥有的学生
private List<Student> students;
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
public Classes(int id, String name, Teacher teacher) {
super();
this.id = id;
this.name = name;
this.teacher = teacher;
}
public Classes(int id) {
super();
this.id = id;
}
public Classes() {
super();
}
@Override
public String toString() {
return "Classes [id=" + id + ", name=" + name + ", teacher=" + teacher
+ ", students=" + students + "]";
}
//注意添加学生集合后,必须重新生成写入
}
package com.hlx.entity;
/**
* 学生类
* @author Administrator
*
*/
public class Student {
private int id; // s_id
private String name; // s_name
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student(int id, String name) {
super();
this.id = id;
this.name = name;
}
public Student() {
super();
}
public Student(int id) {
super();
this.id = id;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
}
(2)定义sql映射文件ClassesMapper.xml
<!-- OneToMany
方式一: 嵌套结果: 使用嵌套结果映射来处理重复的联合结果的子集
SELECT * FROM class c, teacher t,student s where c.c_id = s.class_id and t.t_id=c.teacher_id and c.c_id=1
-->
<select id="getOneToMany" parameterType="int" resultMap="ClassMap3">
select * from class c, teacher t,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id=#{id}
</select>
<resultMap type="com.hlx.entity.Classes" id="ClassMap3">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<!-- 关联老师 -->
<association property="teacher" column="teacher_id" javaType="com.hlx.entity.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
<!-- ofType指定students集合中的对象类型 -->
<collection property="students" ofType="com.hlx.entity.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
</collection>
</resultMap>
<!-- OneToMany
方式二: 嵌套查询:通过执行另外一个SQL映射语句来返回预期的复杂类型
select * from class where c_id=1 //通过c_id=1
select * from teacher where t_id=1 //上一个查询获得teacher_id的值
select * from student where class_id=1 //上一个查询得到的c_id的值 -->
<select id="getOneToMany2" parameterType="int" resultMap="ClassMap4">
select * from class where c_id=#{id}
</select>
<resultMap type="com.hlx.entity.Classes" id="ClassMap4">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<!-- 关联teacher FK column="teacher_id"-->
<association property="teacher" column="teacher_id" select="getTeacher2"/>
<!-- 集合student FK column="c_id" -->
<collection property="students" ofType="com.hlx.entity.Student" column="c_id" select="getStudent"/>
</resultMap>
<!-- teacher -->
<select id="getTeacher2" parameterType="int" resultType="Teacher">
select t_id id,t_name name from teacher where t_id=#{id}
</select>
<!-- student -->
<select id="getStudent" parameterType="int" resultType="Student">
select s_id id,s_name name from student where class_id=#{id}
</select>
(3)测试类
/**
* Classes [id=2, name=Java11, teacher=Teacher [id=2, name=john], students=[Student [id=4, name=cuihua], Student [id=5, name=zhangfei], Student [id=6, name=xionger]]]
*/
@Test
public void getOneToMany1() {
SqlSession session = null;
try {
// 获得会话
session = MyBatisUtil.getSqlSession(true);
// 映射sql的标识字符串
String statement = "com.hlx.mapping.ClassesMapper.getOneToMany";
// 执行插入操作
Classes userinfos = session.selectOne(statement, 2);
logger.debug("查询数据!");
System.out.println(userinfos);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
session.close(); // 对应一次数据库会话,会话结束必须关闭
}
}
/**
*
* Classes [id=1, name=Java10, teacher=Teacher [id=1, name=mike], students=[Student [id=1, name=zhangsan], Student [id=2, name=wangwu], Student [id=3, name=liufei]]]
* */
@Test
public void getOneToMany2() {
SqlSession session = null;
try {
// 获得会话
session = MyBatisUtil.getSqlSession(true);
// 映射sql的标识字符串
String statement = "com.hlx.mapping.ClassesMapper.getOneToMany2";
// 执行插入操作
Classes userinfos = session.selectOne(statement, 1);
logger.debug("查询数据!");
System.out.println(userinfos);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
session.close(); // 对应一次数据库会话,会话结束必须关闭
}
}
其他的步骤省略.............
三、ResultMap标签
SQL 映射XML 文件一些初级的元素
2
3
4
5
6
7
8
|
1. cache – 配置给定模式的缓存
2. cache-ref – 从别的模式中引用一个缓存
3. resultMap – 这是最复杂而却强大的一个元素了,它描述如何从结果集中加载对象
4. sql – 一个可以被其他语句复用的SQL 块
5.
insert
– 映射
INSERT
语句
6.
update
– 映射
UPDATE
语句
7.
delete
– 映射DELEETE 语句
8.
select
- 映射
SELECT
语句
|
|
resultMap可以设置的映射:
1. constructor – 用来将结果反射给一个实例化好的类的构造器
a) idArg – ID 参数;将结果集标记为ID,以方便全局调用
b) arg –反射到构造器的通常结果
2. id – ID 结果,将结果集标记为ID,以方便全局调用
3. result – 反射到JavaBean 属性的普通结果
4. association – 复杂类型的结合;多个结果合成的类型
a) nested result mappings – 几resultMap 自身嵌套关联,也可以引用到一个其它上
5. collection –复杂类型集合a collection
of
complex types
6. nested result mappings – resultMap 的集合,也可以引用到一个其它上
7. discriminator – 使用一个结果值以决定使用哪个resultMap
a)
case
– 基本一些值的结果映射的
case
情形
i. nested result mappings –一个
case
情形本身就是一个结果映射,因此也可以包括一些相同的元素,也可以引用一个外部resultMap。