MyBatis多表关联查询的实现示例

作者:Java 时间:2023-07-06 06:26:49 

MyBatis多表关联查询的实现示例

一对多查询

一对多关联查询是指在查询一方对象的时候,同时将其所关联的多方对象也都查询出来。下面以班级 Classes 与学生 Student 间的一对多关系为例进行演示。一个班级有多个学生,一个学生只属于一个班级。数据库 student 表里面有个字段 classno 是外键,对应主键表 Class 的主键 cid

项目案例:查询班级号为 1801 的班级,同时遍历该班级的所有的学生信息

实现步骤:

【1】在 MySQL 中创建数据库 studentdb,创建表 studentclasses,并添加若干测试用的数据记录,SQL 语句如下:

CREATE DATABASE studentdb;
USE  studentdb ;
DROP TABLE IF EXISTS  student ;
CREATE TABLE  student  (
  id  INT(11) NOT NULL,
  studentname  VARCHAR(20) DEFAULT NULL,
  gender  CHAR(2) DEFAULT NULL,
  age  INT(11) DEFAULT NULL,
  classno VARCHAR(10),
  PRIMARY KEY ( id )
)
INSERT  INTO  student ( id , studentname , gender , age , classno ) VALUES (1,'张飞','男',18,'201801'),(2,'李白','男',20,'201801'),(3,'张无忌','男',19,'201801'),(4,'赵敏','女',17,'201801');

CREATE TABLE classes (
cid VARCHAR (30),
cname VARCHAR (60)
);
INSERT INTO classes (cid, cname) VALUES('201801','计算机软件1班');
INSERT INTO classes (cid, cname) VALUES('201802','计算机软件2班');

【2】创建实体类 ClassesStudent

Student 类如下:

package cn.kgc.my01.entity;

import lombok.Data;

@Data
public class Student {
   private String sid;
   private String sname;
   private String sex;
   private Integer age;

//添加额外属性:所在班级
   private  Classes classes;

public String show(){
       return "学生编号:"+getSid()+",学生姓名:"+getSname()+",学生性别:"+getSex()+",学生年龄:"+getAge();
   }
}

Classes 类如下:

package cn.kgc.my01.entity;

import lombok.Data;

import java.util.List;

@Data
public class Classes {
   private String cid;
   private String cname;

//添加额外属性
   private List<Student> students;

public String show(){
       return "班级编号:"+getCid()+",班级名称:"+getCname()+",班级学生:";
   }
}

【3】创建 ClassesMapper.java 接口,并添加 findClassesById 方法

package cn.kgc.my01.mapper;

import cn.kgc.my01.entity.Classes;

public interface ClassesMapper {
   Classes findClassesById(String id);
}

【4】创建 ClassesMapper.xml 映射文件,有以下两种方式:

方式一:多表连接查询方式

这种方式只用到1条 SQL 语句,代码如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
       PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.kgc.my01.mapper.ClassesMapper">
   <!--方式一:多表连接查询方式,只用到 1条SQL语句-->
   <resultMap id="classResultMap" type="classes">
       <id property="cid" column="cid"/>
       <result property="cname" column="cname"/>
       <!--关联属性的映射关系-->
       <collection property="students" ofType="Student">
           <id property="sid" column="id"/>
           <result property="sname" column="studentname"/>
           <result property="sex" column="gender"/>
           <result property="age" column="age"/>
       </collection>
   </resultMap>
   <select id="findClassesById" resultMap="classResultMap">
       select cid,cname,id,studentname,gender,age from classes,student
       where classes.cid=student.classno and classes.cid=#{cid}
   </select>
</mapper>

注意:<resultMap/> 中,如果字段名与属性名相同时,可以在 <resultMap/> 中添加 autoMapping=&ldquo;true&rdquo; 来开启自动映射。

另外,在 &ldquo;一方&rdquo; 的映射文件中使用 <collection/> 标签体现出两个实体对象间的关联关系。其两个属性的解释如下:

  • property:指定关联属性,即 Class 类中的集合属性 students

  • ofType:集合属性的泛型类型,即 Student

方式二:多表单独查询方式

多表连接查询方式是将多张表进行连接,连为一张表后进行查询。其查询的本质是一张表。而多表单独查询方式是多张表各自查询各自的相关内容,需要多张表的联合数据,再将主表的查询结果联合其它表的查询结果,封装为一个对象。

多个查询是可以跨越多个映射文件的,即是可以跨越多个namespace 的。在使用其它 namespace 的查询时,添加上其所在的 namespace 即可。这种方式要用到2条 SQL 语句,代码如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
       PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.kgc.my01.mapper.ClassesMapper">
  <!--方式二:多表单独查询方式,也就是分步查询-->
   <resultMap id="classResultMap2" type="classes">
       <id property="cid" column="cid"/>
       <result property="cname" column="cname"/>
       <!--关联属性的映射关系-->
       <collection property="students" ofType="Student">
           <id property="sid" column="id"/>
           <result property="sname" column="studentname"/>
           <result property="sex" column="gender"/>
           <result property="age" column="age"/>
       </collection>
   </resultMap>
   <!-- 以 * 释部分属于方式二: 多表单独查询方式 -->
   <resultMap id="studentResultMap" type="student">
       <id property="sid" column="id" />
       <result property="sname" column="studentname" />
       <result property="sex" column="gender" />
       <result property="age" column="age" />
   </resultMap>
   <resultMap id="classesResultMap" type="classes">
       <id property="cid" column="cid" />
       <result property="cname" column="cname" />
   <!-- 关联属性的映射关系 -->
   <!-- 集合的数据来自指定的select查询,该select查询的动态参数来自column指定的字段值 -->
       <collection property="students" ofType="Student" select="selectStudentsByClasses" column="cid"/>
   </resultMap>
   <!-- 多表单独查询,查多方的表 -->
   <select id="selectStudentsByClasses" resultMap="studentResultMap">
       select * from student where calssno=#{cid}
   </select>

<!-- 多表单独查询,查一方的表 -->
    <select id="findClassesById" parameterType="String" resultMap="classesResultMap">
       select cid,cname from classes
       where cid=#{cid}
   </select>
</mapper>

MyBatis多表关联查询的实现示例

【5】创建 ClassesMapperTest 测试类,并添加如下方法:

package cn.kgc.my01.mapper;

import cn.kgc.my01.entity.Classes;
import cn.kgc.my01.entity.Student;
import junit.framework.TestCase;
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.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class ClassesMapperTest{
   SqlSessionFactory factory=null;
   @Before
   public void init(){
       try {
           System.out.println("########");
           InputStream resourceAsStream = Resources.getResourceAsStream("config/mybatis-config.xml");

factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

} catch (IOException e) {
           e.printStackTrace();
       }

}
   @Test
   public void testFindClassesById() {
       SqlSession sqlSession = factory.openSession(true);
       ClassesMapper mapper = sqlSession.getMapper(ClassesMapper.class);
       Classes classesById = mapper.findClassesById("201801");
       System.out.println(classesById.show());
       List<Student> students = classesById.getStudents();

for (Student student : students) {
           System.out.println(student.show());
       }
   }
}

方式一:多表连接查询方式测试结果:

DEBUG [main] - ==>  Preparing: select cid,cname,id,studentname,gender,age from
classes,student where classes.cid=student.classno and classes.cid=?
DEBUG [main] - ==> Parameters: 201801(String)
DEBUG [main] - <==      Total: 4
班级编号:201801,班级名称:计算机软件1班,班级学生:
学生编号:1,学生姓名:张飞,学生性别:男,学生年龄:18
学生编号:2,学生姓名:李白,学生性别:男,学生年龄:20
学生编号:3,学生姓名:张无忌,学生性别:男,学生年龄:19
学生编号:4,学生姓名:赵敏,学生性别:女,学生年龄:17

可以发现,只有一条 SQL 语句,并且是多表联查。

方式二:多表单独查询方式测试结果:

2023-02-15 10:56:49,965 [main] DEBUG DEBUG [main] - ==>  Preparing: select cid,cname from classes where cid=?
DEBUG [main] - ==> Parameters: 201801(String)
DEBUG [main] - ====>  Preparing: select * from student where classno=?
DEBUG [main] - ====> Parameters: 201801(String)
DEBUG [main] - <====      Total: 4
DEBUG [main] - <==      Total: 1
班级编号:201801,班级名称:计算机软件1班,班级学生:
学生编号:1,学生姓名:张飞,学生性别:男,学生年龄:18
学生编号:2,学生姓名:李白,学生性别:男,学生年龄:20
学生编号:3,学生姓名:张无忌,学生性别:男,学生年龄:19
学生编号:4,学生姓名:赵敏,学生性别:女,学生年龄:17

可以发现,其 SQL 语句是两条,即各查各的,共用同一个参数。第 1 条先查一方的表,第 2 条再查多方的表。

多对一查询

多对一关联查询是指在查询多方对象的时候,同时将其所关联的一方对象也查询出来。

由于在查询多方对象时也是一个一个查询,所以多对一关联查询,其实就是一对一关联查询。即一对一关联查询的实现方式与多对一的实现方式是相同的。 配置多对一关联的重点在于&ldquo;多方&rdquo;的映射文件要有 <association> 属性关联&ldquo;一方&rdquo;。

项目案例: 查询学号为1的学生,同时获取他所在班级的完整信息

实现步骤:

【1】创建 StudentMapper.java 接口,并添加方法 searchStudentsById(int id) 如下:

package cn.kgc.my01.mapper;

import cn.kgc.my01.entity.Student;

public interface StudentMapper {
   public Student searchStudentsById(int id);
}

【2】创建 StudentMapper.xml 映射文件,有以下两种方式:

方式一:多表联合查询。

<!-- 多表联合查询 -->
   <resultMap id="studentResultMapper" type="student">
       <id property="sid" column="id" />
       <result property="sname" column="studentname" />
       <result property="sex" column="gender" />
       <result property="age" column="age" />
       <!-- 关联属性 -->
       <association property="classes" javaType="classes">
           <id property="cid" column="cid" />
           <result property="cname" column="cname" />
       </association>
   </resultMap>
   <!-- 多表连接查询 -->
   <select id="searchStudentsById" parameterType="int" resultMap="studentResultMapper">
       select cid,cname,id,studentname,gender,age from classes,student
       where classes.cid=student.classno
       and student.id=#{id}
   </select>

方式二:多表单独查询。

<!-- 以 * 释的是方式二:多表单独查询 -->
   <resultMap id="studentResultMap2" type="student">
       <id property="sid" column="id" />
       <result property="sname" column="studentname" />
       <result property="sex" column="gender" />
       <result property="age" column="age" />
       <!-- 关联属性 -->
       <association property="classes" javaType="classes" select="findClassesById" column="classno"/>
   </resultMap>
   <select id="searchStudentsById" resultMap="studentResultMap2">
       select id,studentname,gender,age,classno from student where id=#{id}
   </select>
   <select id="findClassesById" parameterType="String" resultType="classes">
       select cid,cname from classes where cid=#{cid}
   </select>

MyBatis多表关联查询的实现示例

【3】创建 StudentMapperTest 测试类,并添加如下方法:

package cn.kgc.my01.mapper;

import cn.kgc.my01.entity.Classes;
import cn.kgc.my01.entity.Student;
import junit.framework.TestCase;
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.junit.Before;
import org.junit.Test;

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

public class StudentMapperTest {
   SqlSessionFactory factory=null;
   @Before
   public void init(){
       try {
           InputStream resourceAsStream = Resources.getResourceAsStream("config/mybatis-config.xml");

factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

} catch (IOException e) {
           e.printStackTrace();
       }

}

@Test
   public void testSearchStudentsById() {
       SqlSession sqlSession = factory.openSession(true);
       StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
       Student student = mapper.searchStudentsById(1);
       System.out.println(student.show());

System.out.println("所在班级:");
       Classes classes=student.getClasses();
       System.out.println(classes.toString());
   }
}

方式一:多表联合查询方式测试结果:

DEBUG [main] - ==>  Preparing: select cid,cname,id,studentname,gender,age from
    classes,student where classes.cid=student.classno and student.id=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
学生编号:1,学生姓名:张飞,学生性别:男,学生年龄:18
所在班级:
Classes(cid=201801, cname=计算机软件1班, students=null)

可以发现,它发出的 SQL 语句是多表查询。

方式一:多表单独查询方式测试结果:

DEBUG [main] - ==>  Preparing: select id,studentname,gender,age,classno from student where id=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - ====>  Preparing: select cid,cname from classes where cid=?
DEBUG [main] - ====> Parameters: 201801(String)
DEBUG [main] - <====      Total: 1
DEBUG [main] - <==      Total: 1
学生编号:1,学生姓名:张飞,学生性别:男,学生年龄:18
所在班级:
Classes(cid=201801, cname=计算机软件1班, students=null)

可以发现,它发出的 SQL 语句是两条,即各查各的,共用同一个参数。

自连接查询

自连接的查询可以用一对多来处理,也可以用多对一来处理。例如,员工表,每个员工都有一个上司,但上司同时也是员工表的一条记录,这种情况可用自连接查询出每个员工对应的上司信息,也可以查出每个上司有哪些下属员工。

使用多对一的方式实现自连接

项目案例:查询员工的信息及对应的上司信息。

思路分析: 可将员工当做多方,上司当做一方。

实现步骤:

【1】修改数据库。

添加一个表 employee 并插入测试数据,具体如下:

create table employee (
empid double ,
empname varchar (60),
job varchar (60),
leader double
);
insert into employee (empid, empname, job, leader) values('1','jack','clerk','3');
insert into employee (empid, empname, job, leader) values('2','mike','salesman','3');
insert into employee (empid, empname, job, leader) values('3','john','manager','4');
insert into employee (empid, empname, job, leader) values('4','smith','president',NULL);
insert into employee (empid, empname, job, leader) values('5','rose','salesman','3');

【2】创建实体类 Employee,代码如下:

package cn.kgc.my01.entity;

public class Employee {
private int empid;
private String empname;
private String job;
private Employee leader;
public int getEmpid() {
return empid;
}
public void setEmpid(int empid) {
this.empid = empid;
}
public String getEmpname() {
return empname;
}
public void setEmpname(String empname) {
this.empname = empname;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Employee getLeader() {
return leader;
}
public void setLeader(Employee leader) {
this.leader = leader;
}
public String toString(){
return "员工编号:"+getEmpid()+",员工姓名:"+getEmpname()+",员工职位:"+getJob();
}
}

可以发现,里面存在着嵌套,Employee 里面的一个属性 leader 本身就是 Employee 类型。

【3】创建 EmployeeMapper.java 接口,添加 findEmployeeAndLeaderById 方法如下:

package cn.kgc.my01.mapper;

import cn.kgc.my01.entity.Employee;

public interface EmployeeMapper {
   Employee findEmployeeAndLeaderById(int id);
}

【4】创建 EmployeeMapper.xml 映射文件,代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
       PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.kgc.my01.mapper.EmployeeMapper">

<resultMap id="empResultMap" type="employee">
       <id property="empid" column="empid" />
       <result property="empname" column="empname" />
       <result property="job" column="job" />
       <association property="leader" javaType="Employee"
                    select="findEmployeeAndLeaderById" column="leader"/>
   </resultMap>
   <select id="findEmployeeAndLeaderById" parameterType="int" resultMap="empResultMap">
       select * from employee where empid=#{empid}
   </select>
</mapper>

【5】创建 EmployeeMapperTest.java 测试类

package cn.kgc.my01.mapper;

import cn.kgc.my01.entity.Classes;
import cn.kgc.my01.entity.Employee;
import cn.kgc.my01.entity.Student;
import junit.framework.TestCase;
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.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

public class EmployeeMapperTest {
   SqlSessionFactory factory=null;
   @Before
   public void init(){
       try {
           InputStream resourceAsStream = Resources.getResourceAsStream("config/mybatis-config.xml");

factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

} catch (IOException e) {
           e.printStackTrace();
       }

}

@Test
   public void testFindEmployeeAndLeaderById() {
       SqlSession sqlSession = factory.openSession(true);
       EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
       Employee employee=mapper.findEmployeeAndLeaderById(1);
       Employee leader=employee.getLeader();
       System.out.println(employee.toString());
       System.out.println("他的上司是:"+leader.toString());
       //System.out.println("他的上司的上司是:"+leader.getLeader().toString());
   }
}

测试结果: 查询员工

DEBUG [main] - ==>  Preparing: select * from employee where empid=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - ====>  Preparing: select * from employee where empid=?
DEBUG [main] - ====> Parameters: 3(Integer)
DEBUG [main] - ======>  Preparing: select * from employee where empid=?
DEBUG [main] - ======> Parameters: 4(Integer)
DEBUG [main] - <======      Total: 1
DEBUG [main] - <====      Total: 1
DEBUG [main] - <==      Total: 1
员工编号:1,员工姓名:jack,员工职位:clerk
他的上司是:员工编号:3,员工姓名:john,员工职位:manager

从上面的 SQL 语句中发现,出现了 3 条 SQL 语句,这个查询存在嵌套,先查员工1,然后查他的直接上司3,再查上司的上司4。这种情况不影响什么,甚至可以实现直接输出上司的上司,但要注意输出语句不要出现地柜,即输出语句不要出现输出上司。

要同时查上司的上司,只需要在上面的测试类中多加一条语句:

System.out.println("他的上司的上司是:"+leader.getLeader().toString());

使用一对多的方式实现自连接

项目案例:查询某位领导及其直接下属员工。

思路分析: 可用一对多的方式来实现,员工(领导)当作一方,员工(下属)当作多方。

实现步骤:

【1】修改实体类 Employee,代码如下:

package cn.kgc.my01.entity;

import java.util.List;

public class Employee {
private int empid;
private String empname;
private String job;
//员工的上司
private Employee leader;

//员工的下属
private List<Employee> employees;
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
public int getEmpid() {
return empid;
}
public void setEmpid(int empid) {
this.empid = empid;
}
public String getEmpname() {
return empname;
}
public void setEmpname(String empname) {
this.empname = empname;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Employee getLeader() {
return leader;
}
public void setLeader(Employee leader) {
this.leader = leader;
}
public String toString(){
return "员工编号:"+getEmpid()+",员工姓名:"+getEmpname()+",员工职位:"+getJob();
}
}

【2】在 EmployeeMapper.java 接口中,添加 findLeaderAndEmployeesById 方法如下:

Employee findLeaderAndEmployeesById(int id);

【3】在 EmployeeMapper.xml 映射文件中,添加 findEmployeeAndLeaderById 的映射方法内容如下:

<!-- 一对多的方式实现自连接 -->
   <resultMap id="empResultMap2" type="employee">
       <id property="empid" column="empid" />
       <result property="empname" column="empname" />
       <result property="job" column="job" />
       <!-- 关联属性的映射关系
       集合的数据来自指定的select查询,该select查询的动态参数来自column指定的字段值 -->
       <collection property="employees" ofType="employee"
                   select="selectEmployeesByLeader" column="empid"/>
   </resultMap>
   <select id="selectEmployeesByLeader" resultType="employee">
       select * from employee where leader=#{empid}
   </select>
   <select id="findLeaderAndEmployeesById" parameterType="int" resultMap="empResultMap2">
       select * from employee where empid=#{empid}
   </select>

【4】在 EmployeeMapperTest.java 测试类中,添加如下内容:

@Test
   public void testTestFindLeaderAndEmployeesById() {
       SqlSession sqlSession = factory.openSession(true);
       EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
       Employee leader=mapper.findLeaderAndEmployeesById(4);
       List<Employee> employees = leader.getEmployees();
       System.out.println(leader.toString());
       System.out.println("他的直接下属有:");
       for (Employee employee : employees) {
           System.out.println(employee.toString());
       }
   }

测试结果: 查询经理

DEBUG [main] - ==>  Preparing: select * from employee where empid=?
DEBUG [main] - ==> Parameters: 4(Integer)
DEBUG [main] - ====>  Preparing: select * from employee where leader=?
DEBUG [main] - ====> Parameters: 4.0(Double)
DEBUG [main] - <====      Total: 1
DEBUG [main] - <==      Total: 1
员工编号:4,员工姓名:smith,员工职位:president
他的直接下属有:
员工编号:3,员工姓名:john,员工职位:manager

多对多查询

原理: 多对多可以分拆成两个一对多来处理,需要一个中间表,各自与中间表实现一对多的关系。

项目案例:一个学生可以选人修多门课程,一门课程可以给多个学生选修,课程与学生之间是典型的多对多。实现查询一个学生信息,同时查出他的所有选修课,还有实现查询一门课程信息,同时查出所有的选修了该课程的学生信息。

思路分析: 多对多需要第三表来体现,数据库中除了课程表,学生表,还需要学生课程表。

实现步骤:

【1】修改数据库,代码如下:

CREATE DATABASE studentdb;
USE  studentdb ;
DROP TABLE IF EXISTS  student ;
CREATE TABLE  student  (
  id  INT(11) NOT NULL,
  studentname  VARCHAR(20) DEFAULT NULL,
  gender  CHAR(2) DEFAULT NULL,
  age  INT(11) DEFAULT NULL,
  classno VARCHAR(10),
  PRIMARY KEY ( id )
)
INSERT  INTO  student ( id , studentname , gender , age , classno ) VALUES (1,'张飞','男',18,'201801'),(2,'李白','男',20,'201801'),(3,'张无忌','男',19,'201801'),(4,'赵敏','女',17,'201801');

CREATE TABLE classes (
cid VARCHAR (30),
cname VARCHAR (60)
);
INSERT INTO classes (cid, cname) VALUES('201801','计算机软件1班');
INSERT INTO classes (cid, cname) VALUES('201802','计算机软件2班');

CREATE TABLE employee (
empid DOUBLE ,
empname VARCHAR (60),
job VARCHAR (60),
leader DOUBLE
);
INSERT INTO employee (empid, empname, job, leader) VALUES('1','jack','clerk','3');
INSERT INTO employee (empid, empname, job, leader) VALUES('2','mike','salesman','3');
INSERT INTO employee (empid, empname, job, leader) VALUES('3','john','manager','4');
INSERT INTO employee (empid, empname, job, leader) VALUES('4','smith','president',NULL);
INSERT INTO employee (empid, empname, job, leader) VALUES('5','rose','salesman','3');

CREATE TABLE course (
courseid DOUBLE ,
coursename VARCHAR (90)
);
INSERT INTO course (courseid, coursename) VALUES('1','java');
INSERT INTO course (courseid, coursename) VALUES('2','android');
INSERT INTO course (courseid, coursename) VALUES('3','PHP');

CREATE TABLE studentcourse (
id DOUBLE ,
studentid DOUBLE ,
courseid DOUBLE
);
INSERT INTO studentcourse (id, studentid, courseid) VALUES('1','1','1');
INSERT INTO studentcourse (id, studentid, courseid) VALUES('2','1','2');
INSERT INTO studentcourse (id, studentid, courseid) VALUES('3','2','1');
INSERT INTO studentcourse (id, studentid, courseid) VALUES('4','2','2');
INSERT INTO studentcourse (id, studentid, courseid) VALUES('5','3','1');
INSERT INTO studentcourse (id, studentid, courseid) VALUES('6','3','2');
INSERT INTO studentcourse (id, studentid, courseid) VALUES('7','1','3');

【2】新增实体类 Course 和修改实体类 Student 。

Course 类如下:

package cn.kgc.my01.entity;

import lombok.Data;

import java.util.List;

@Data
public class Course {
   private int courseid;
   private String coursename;
   private List<Student> students;

public String toString(){
       return "课程编号:"+getCourseid()+",课程名称:"+getCoursename();
   }
}

Student类如下,添加一个属性courses和getter,setter方法。

private List<Course> courses;
   public List<Course> getCourses() {
       return courses;
   }
   public void setCourses(List<Course> courses) {
       this.courses = courses;
   }

【3】新建 StudentMapper.java 接口,并添加一个方法如下:

package cn.kgc.my01.mapper;

import cn.kgc.my01.entity.Student;

public interface StudentMapper {
   public Student searchStudentById(int id);
}

【4】配置对应的 StudentMapper.xml 映射,代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
       PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.kgc.my01.mapper.StudentMapper">
   <resultMap id="studentMap2" type="student">
       <id property="sid" column="id" />
       <result property="sname" column="studentname" />
       <result property="sex" column="gender" />
       <result property="age" column="age" />

<!-- 关联属性的映射关系 -->
       <collection property="courses" ofType="Course">
           <id property="courseid" column="courseid" />
           <result property="coursename" column="coursename" />
       </collection>
   </resultMap>
   <!-- 多表连接查询 -->
   <select id="searchStudentById" parameterType="int" resultMap="studentMap2">
       select student.id,studentname,gender,age,course.courseid,coursename from course,student,studentcourse
       where course.courseid=studentcourse.courseid
       and student.id=studentcourse.studentid and student.id=#{id}
   </select>
</mapper>

【5】创建测试类 StudentMapperTest 类

package cn.kgc.my01.mapper;

import cn.kgc.my01.entity.Classes;
import cn.kgc.my01.entity.Course;
import cn.kgc.my01.entity.Student;
import junit.framework.TestCase;
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.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class StudentMapperTest {
   SqlSessionFactory factory=null;
   @Before
   public void init(){
       try {
           InputStream resourceAsStream = Resources.getResourceAsStream("config/mybatis-config.xml");

factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

} catch (IOException e) {
           e.printStackTrace();
       }

}

@Test
   public void testSearchStudentsById() {
       SqlSession sqlSession = factory.openSession(true);
       StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
       Student student = mapper.searchStudentById(1);
       System.out.println(student.show());

System.out.println("-----该生选修了以下课程:-----------");
       List<Course> courses=student.getCourses();
       for(Course course:courses){
           System.out.println(course.toString());
       }
   }
}

测试结果:

MyBatis多表关联查询的实现示例

【6】新建 CourseMapper.java 接口,并添加一个方法如下:

package cn.kgc.my01.mapper;

import cn.kgc.my01.entity.Course;

public interface CourseMapper {
   //根据id查找课程,即时获取选个性该课程的学生
   public Course searchCourseById(int id);
}

【7】配置对应的 CourseMapper.xml 映射,代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
       PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.kgc.my01.mapper.CourseMapper">
 <resultMap id="courseMap" type="course">
   <id property="courseid" column="courseid" />
   <result property="coursename" column="coursename" />
   <!-- 关联属性的映射关系 -->
   <collection property="students" ofType="Student">
     <id property="sid" column="id" />
     <result property="sname" column="studentname" />
     <result property="sex" column="gender" />
     <result property="age" column="age" />
   </collection>
 </resultMap>

<!-- 多表连接查询 -->
 <select id="searchCourseById" parameterType="int" resultMap="courseMap">
   select student.id,studentname,gender,age,course.courseid,coursename from course,student,studentcourse
   where course.courseid=studentcourse.courseid
   and student.id=studentcourse.studentid and course.courseid=#{courseid}
 </select>
</mapper>

【8】创建测试类 CourseMapperTest 类

package cn.kgc.my01.mapper;

import cn.kgc.my01.entity.Course;
import cn.kgc.my01.entity.Employee;
import cn.kgc.my01.entity.Student;
import junit.framework.TestCase;
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.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class CourseMapperTest{
   SqlSessionFactory factory=null;
   @Before
   public void init(){
       try {
           InputStream resourceAsStream = Resources.getResourceAsStream("config/mybatis-config.xml");

factory = new SqlSessionFactoryBuilder().build(resourceAsStream);

} catch (IOException e) {
           e.printStackTrace();
       }

}

@Test
   public void testSearchCourseById() {
       SqlSession sqlSession = factory.openSession(true);
       CourseMapper mapper = sqlSession.getMapper(CourseMapper.class);
       Course course = mapper.searchCourseById(1);
       System.out.println(course.toString());
       System.out.println("-------该课程有以下学生选修:------");
       List<Student> students=course.getStudents();
       for(Student student:students){
           System.out.println(student.show());
       }
   }
}

测试效果:

MyBatis多表关联查询的实现示例

来源:https://blog.csdn.net/hh867308122/article/details/129005131

标签:MyBatis,多表,关联,查询
0
投稿

猜你喜欢

  • 深入理解C# DateTime日期格式化

    2021-12-08 04:23:17
  • Android EventBus(普通事件/粘性事件)详解

    2022-12-22 18:48:09
  • Android编程实现手机自带内部存储路径的获取方法

    2022-05-14 11:59:11
  • 详解JavaWeb中的 Listener

    2023-09-04 08:09:24
  • C# 正则表达式常用的符号和模式解析(最新推荐)

    2021-07-05 16:01:22
  • kotlin延迟初始化和密封类详细讲解

    2022-07-10 01:53:52
  • IntelliJ IDEA中显示和关闭工具栏与目录栏的方法

    2023-09-01 23:18:59
  • Android如何使用Bmob后端云实现失物招领功能

    2023-10-15 07:28:05
  • java实现打砖块小游戏

    2021-07-26 14:47:11
  • Android 动画实现几种方案

    2022-08-31 02:57:39
  • c# rsa加密解密详解

    2023-06-11 00:54:17
  • spring validation多层对象校验教程

    2023-11-27 15:17:49
  • android自定义ImageView仿图片上传示例

    2023-08-11 20:34:08
  • Android自定义View实现渐变色进度条

    2022-11-25 08:27:17
  • 详解Android自定义控件属性TypedArray以及attrs

    2023-06-20 05:13:41
  • C# 中的动态创建组件(属性及事件)的实现思路及方法

    2021-07-20 04:58:31
  • java中的各种修饰符作用及范围

    2022-02-10 01:03:54
  • C#中通过Command模式实现Redo/Undo方案

    2021-07-12 14:58:59
  • java struts2学习笔记之线程安全

    2022-08-07 00:13:07
  • 微信小程序获取手机号,后端JAVA解密流程代码

    2023-11-29 07:57:26
  • asp之家 软件编程 m.aspxhome.com