文章目录
Mybatis 多对一 and 一对多查询详解
数据库
员工表 t_emp
部门表 t_dept
sql
CREATE TABLE `t_emp` (
`emp_id` int NOT NULL AUTO_INCREMENT,
`emp_name` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`age` int DEFAULT NULL,
`gender` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`dept_id` int DEFAULT NULL,
PRIMARY KEY (`emp_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
CREATE TABLE `t_dept` (
`dept_id` int NOT NULL AUTO_INCREMENT,
`dept_name` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
PRIMARY KEY (`dept_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `t_emp` (`emp_id`, `emp_name`, `age`, `gender`, `dept_id`) VALUES (1, '张三', 20, '男', 1), (2, '李四', 22, '男', 2), (3, '王五', 23, '男', 3), (4, '赵六', 24, '男', 1);
INSERT INTO `t_dept` (`dept_id`, `dept_name`) VALUES (1, 'A'), (2, 'B'), (3, 'C');
需求
多对一:员工表对应部门表
查询指定id的员工以及其对应的部门
一对多:部门表对应员工表
查询指定的部门以及其包含的员工
Mybatis代码
DeptMapper接口文件
java
package com.atguigu.mybatis.mapper;
import com.ruanjian.pojo.Dept;
import com.ruanjian.pojo.Emp;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface DeptMapper {
// 一对多查询
// 查询部门表中的员工信息
// 需要在部门类中添加员工的集合 private List<Emp> emps;
Dept getDeptAndEmpById(@Param("deptId") Integer deptId);
// 分步查询
// 1.先查出指定id的部门信息,部门信息中有对应员工的dept_id
Dept getDeptAndEmpByStepOne(@Param("deptId") int deptId);
// 2.再根据dept_id查出相对应的员工信息
List<Emp> getDeptAndEmpByStepTwo(@Param("deptId") int deptId);
}
EmpMapper接口文件
java
package com.atguigu.mybatis.mapper;
import com.ruanjian.pojo.Dept;
import com.ruanjian.pojo.Emp;
import org.apache.ibatis.annotations.Param;
public interface EmpMapper {
// 多对一查询
// 查询指定id员工以及该员工所对应的部门信息
Emp getEmpAndDeptById(@Param("empId") Integer empId);
Emp getEmpAndDeptById_association(@Param("empId") Integer empId);
// 分步查询
// 先从员工表中查询出指定id的员工的数据,该数据中有对应部门id
// 再根据部门id从部门表中查询出对应的部门信息
// 分步查询第一步
Emp getEmpAndDeptByIdOne(@Param("empId") Integer empId);
// 分步查询第二步
Dept getEmpAndDeptByIdTwo(@Param("deptId") Integer deptId);
}
Dept类文件 部门实体类
java
package com.ruanjian.pojo;
/*
员工对部门 是多对一,多对一是在多的那个类(员工类)中添加一个部门对象
部门对员工 是一对多,一对多是在一的那个类中(部门类)中添加一个员工集合
对一 对的就是一个对象
对多 对的就是一个集合
*/
import java.util.List;
// 部门实体类
public class Dept {
private Integer deptId;
private String deptName;
private List<Emp> emps; // 添加的一个员工的集合
public Dept() {
}
public Dept(Integer deptId, String deptName) {
this.deptId = deptId;
this.deptName = deptName;
}
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public List<Emp> getEmps() {
return emps;
}
public void setEmps(List<Emp> emps) {
this.emps = emps;
}
@Override
public String toString() {
return "Dept{" +
"deptId=" + deptId +
", deptName='" + deptName + '\'' +
", emps=" + emps +
'}';
}
}
Emp类文件
员工实体类
java
package com.ruanjian.pojo;
/*
员工对部门 是多对一,多对一是在多的那个类(员工类)中添加一个部门对象
部门对员工 是一对多,一对多是在一的那个类中(部门类)中添加一个员工集合
对一 对的就是一个对象
对多 对的就是一个集合
*/
// 员工实体类
// 对一就是对应的一个对象
// 对多就是对应的一个集合
public class Emp {
private Integer empId;
private String empName;
private Integer age;
private String gender;
private Dept dept; // 加上一个部门的对象
public Emp() {
}
public Emp(Integer empId, String empName, Integer age, String gender) {
this.empId = empId;
this.empName = empName;
this.age = age;
this.gender = gender;
}
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"empId=" + empId +
", empName='" + empName + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", dept=" + dept +
'}';
}
}
DeptMapper
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.atguigu.mybatis.mapper.DeptMapper">
<!-- 处理一对多的映射关系
1. collection
2. 分步查询
-->
<!--*************************** 一对多 collection ****************************************-->
<resultMap id="deptAndEmpById_resultMap" type="dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
<!-- collection : 处理一对多的映射关系(处理集合类型的属性)-->
<!-- ofType表示的是集合中的类型-->
<collection property="emps" ofType="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
</collection>
</resultMap>
<!-- Dept getDeptAndEmpById(@Param("deptId") Integer deptId);-->
<select id="getDeptAndEmpById" resultMap="deptAndEmpById_resultMap">
select *
from t_dept
left join t_emp on t_dept.dept_id = t_emp.dept_id
where t_dept.dept_id=#{deptId}
</select>
<!--*************************** 一对多 collection ****************************************-->
<!--*************************** 一对多 分步查询 ****************************************-->
<resultMap id="deptAndEmpResultMapByStep" type="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
<collection property="emps"
select="com.atguigu.mybatis.mapper.DeptMapper.getDeptAndEmpByStepTwo"
column="dept_id"></collection>
</resultMap>
<!-- Dept getDeptAndEmpByStepOne(@Param("deptId") int deptId);
// 先查出指定id的部门信息,部门信息中有对应员工的dept_id -->
<select id="getDeptAndEmpByStepOne" resultMap="deptAndEmpResultMapByStep">
select * from t_dept where dept_id = #{deptId}
</select>
<!-- List<Emp> getDeptAndEmpByStepTwo(@Param("deptId") int deptId);
// 再根据dept_id查出相对应的员工信息-->
<select id="getDeptAndEmpByStepTwo" resultType="Emp">
select * from t_emp where dept_id = #{deptId}
</select>
</mapper>
EmpMapper
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.atguigu.mybatis.mapper.EmpMapper">
<!--
处理多对一的映射关系
有三种方法:
第一种:级联方式处理
第二种:association 处理多对一的映射关系(处理的是实体类类型的属性)
第三种:分布查询
-->
<!-- ************ 第一种:级联方式处理 *************** -->
<resultMap id="EmpAndDeptById_resultMap" type="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<result column="dept_id" property="dept.deptId"></result>
<result column="dept_name" property="dept.deptName"></result>
</resultMap>
<!--Emp getEmpAndDeptById(@Param("empId") Integer empId);-->
<select id="getEmpAndDeptById" resultMap="EmpAndDeptById_resultMap">
select *
from t_emp
left join t_dept on t_emp.dept_id = t_dept.dept_id
where t_emp.emp_id=#{empId}
</select>
<!-- *********************************************-->
<!-- *************** 第二种 association ******************************-->
<!-- 第二种 association-->
<resultMap id="getEmpAndDeptById_association_resultMap" type="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<!--
association: 处理多对一的映射关系(处理实体类类型的属性)
property: 设置需要处理映射关系的属性的属性名
javaType: 设置要处理的属性的类型, 就是把<association>标签下设置映射关系的字段,封装给某个类
-->
<association property="dept" javaType="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
</association>
</resultMap>
<!-- Emp getEmpAndDeptById_association(@Param("empId") Integer empId);-->
<select id="getEmpAndDeptById_association" resultMap="getEmpAndDeptById_association_resultMap">
select *
from t_emp
left join t_dept on t_emp.dept_id = t_dept.dept_id
where t_emp.emp_id=#{empId}
</select>
<!-- *********************************************-->
<!-- ****************** 第三种:分布查询 ***************************-->
<resultMap id="getEmpAndDeptByIdOne_resultMap" type="Emp">
<id column="emp_id" property="empId"></id>
<result column="emp_name" property="empName"></result>
<result column="age" property="age"></result>
<result column="gender" property="gender"></result>
<!--
property: 设置需要处理映射关系的属性的属性名
select: 填写分步查询的sql的唯一标识,就是设置下一步要执行的sql语句
column: 将上一个sql查询出的某个字段作为分步查询的下一个sql语句sql条件,相当于函数的参数,传给下一个sql语句
fetchType: 在开启了延时加载的环境中,通过该属性设置当前的分步查询是否使用延迟加载
有两个值:eager(立即加载) lazy(延迟加载)
-->
<association property="dept"
fetchType="eager"
select="com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByIdTwo"
column="dept_id">
</association>
</resultMap>
<!-- Emp getEmpAndDeptByIdOne(@Param("empId") Integer empId);-->
<select id="getEmpAndDeptByIdOne" resultMap="getEmpAndDeptByIdOne_resultMap">
select * from t_emp where emp_id = #{empId}
</select>
<!-- Dept getEmpAndDeptByIdTwo(@Param("deptId") Integer deptId);-->
<select id="getEmpAndDeptByIdTwo" resultType="Dept">
select * from t_dept where dept_id = #{deptId}
</select>
<!-- *********************************************-->
</mapper>
ResultMapTest
java
import com.atguigu.mybatis.mapper.DeptMapper;
import com.atguigu.mybatis.mapper.EmpMapper;
import com.ruanjian.pojo.Dept;
import com.ruanjian.pojo.Emp;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
public class ResultMapTest {
private SqlSession session;
/*
处理多对一的映射关系
有三种方法:
第一种:级联方式处理
第二种:association 处理多对一的映射关系(处理的是实体类类型的属性)
第三种:分步查询
*/
// *********************** 多对一 ****************************************
@Test
// 第三种:分步查询
public void textGetEmpAndDeptByIdOne() {
EmpMapper mapper = session.getMapper(EmpMapper.class);
Emp emp = mapper.getEmpAndDeptByIdOne(1);
System.out.println(emp);
}
@Test
// 第二种:association
public void textGetEmpAndDeptById_association() {
EmpMapper mapper = session.getMapper(EmpMapper.class);
Emp emp = mapper.getEmpAndDeptById_association(2);
System.out.println(emp);
}
@Test
// 第一种:级联方式处理
public void textGetEmpAndDeptById() {
EmpMapper mapper = session.getMapper(EmpMapper.class);
Emp emp = mapper.getEmpAndDeptById(2);
System.out.println(emp);
}
// *********************** 一对多 ****************************************
@Test
// 分步查询
public void textGetDeptAndEmpByStep() {
DeptMapper mapper = session.getMapper(DeptMapper.class);
Dept dept = mapper.getDeptAndEmpByStepOne(2);
System.out.println(dept);
}
@Test
// 一对多查询
public void textGetDeptAndEmpById() {
DeptMapper mapper = session.getMapper(DeptMapper.class);
Dept dept = mapper.getDeptAndEmpById(1);
System.out.println(dept);
}
// ***************************************************************
// junit会在每一个@Test方法前执行@Before方法
@Before
public void init() throws IOException {
session = new SqlSessionFactoryBuilder()
.build(
Resources.getResourceAsStream("mybatis-config.xml"))
.openSession();
}
// junit会在每一个@Test方法后执行@After方法
@After
public void clear() {
session.commit();
session.close();
}
}
db.properties
xml
mysql.driver=com.mysql.cj.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false
mysql.username=root
mysql.password=123456
log4j.xml
xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n"/>
</layout>
</appender>
<logger name="java.sql">
<level value="debug"/>
</logger>
<logger name="org.apache.ibatis">
<level value="info"/>
</logger>
<root>
<level value="debug"/>
<appender-ref ref="STDOUT"/>
</root>
</log4j:configuration>
mybatis-config.xml
xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--环境配置-->
<!--引入外部db.properties-->
<properties resource="db.properties"/>
<settings>
<!-- <setting name="cacheEnabled" value="true" />-->
<!-- 开启延时加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 开启时即为true时任何方法的调用都会加载相关类的全部属性
false时是按需加载,true是全部加载
-->
<setting name="aggressiveLazyLoading" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
<package name="com.ruanjian.pojo"/>
</typeAliases>
<!--配置mybatis的连接环境(可以配置多个环境)-->
<environments default="development">
<!--开发环境-->
<environment id="development">
<!--使用JDBC事务管理-->
<transactionManager type="JDBC"/>
<!--数据库连接相关配置,db.properties文件中的内容-->
<!--使用连接池技术-->
<dataSource type="POOLED">
<!--数据库驱动-->
<property name="driver" value="${mysql.driver}"/>
<!--连接字符串-->
<property name="url" value="${mysql.url}"/>
<!--数据库用户名-->
<property name="username" value="${mysql.username}"/>
<!--数据库密码-->
<property name="password" value="${mysql.password}"/>
</dataSource>
</environment>
</environments>
<!--mapping文件路径配置-->
<mappers>
<!-- <mapper resource="mapper/DeptMapper.xml"/>-->
<package name="com.atguigu.mybatis.mapper"/>
</mappers>
</configuration>
pom.xml
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>MyBaits_2</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<maven.compiler.sourece>11</maven.compiler.sourece>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>text</scope>
</dependency>
<!-- log4j日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
注意
新建包时用点
例如:com.atguigu.mybatis.mapper
resources目录下建立多层目录的时候时是用分割线
例如:com/atguigu/mybatis/mapper
mybatis-config.xml文件中
bash
<package name="com.atguigu.mybatis.mapper"/>
<package>的使用条件:
接口文件要和xml文件同名,并且在同一个目录下
使用注解写的接口,只能有class的方式注册,例:
bash
<mapper class="com.atguigu.mybatis.mapper.DeptMapper"></mapper>