Mybatis关联表查询_5

使用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>

在mybatis-conf.xml文件中注册ClassesMapper.xml
<!-- 将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属性:type为java实体类;id为此resultMap的标识。
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。


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mybatis的级联查询可以通过在Mapper文件中使用嵌套查询的方式实现,具体步骤如下: 1. 在POJO类中定义联属性(如一对多、多对多等),并提供对应的setter和getter方法。 2. 在Mapper文件中定义对应的嵌套查询语句,使用联属性的getter方法来获取联对象的数据,例如: ```xml <select id="findUserById" parameterType="int" resultMap="userResultMap"> select * from user where id = #{id} </select> <resultMap id="userResultMap" type="User"> <id column="id" property="id"/> <result column="username" property="username"/> <result column="age" property="age"/> <association property="department" javaType="Department"> <id column="dept_id" property="id"/> <result column="dept_name" property="name"/> </association> </resultMap> <select id="findUserWithDeptById" parameterType="int" resultMap="userResultMap"> select u.*, d.dept_name from user u left join department d on u.dept_id = d.id where u.id = #{id} </select> ``` 在上述代码中,`findUserById`只查询User中的数据,而`findUserWithDeptById`则查询User和Department中的数据,并将Department作为User对象的联属性返回。 3. 在业务层中调用Mapper接口的方法,即可进行级联查询,例如: ```java User user = userMapper.findUserWithDeptById(1); System.out.println(user.getDepartment().getName()); ``` 在上述代码中,`userMapper.findUserWithDeptById`方法会返回一个User对象,其中的Department属性已经被赋值为联的Department对象,通过getDepartment()方法即可获取Department对象的数据。 需要注意的是,在进行级联查询时,需要定义好联属性的类型和对应的嵌套查询语句,否则会导致查询失败或数据不完整。同时,级联查询也会增加数据库的查询开销,应该根据实际情况进行使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值