一、一对多查询
一对多查询的环境仍基于上一篇,一个部门可以有多个员工,一对多的实现方式也有三种,与一对一查询的方式一致,不同的是一对一查询使用的式association,一对多使用的是collection。
方式一:嵌套查询
(1)给Dept添加集合属性 empList,并提供get和set方法,覆写toString;去掉Emp中的dept属性和与之相关的方法。
public class Dept {
private Integer id;
private String deptName;
private String deptDesc;
private List<Emp> empList;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getDeptDesc() {
return deptDesc;
}
public void setDeptDesc(String deptDesc) {
this.deptDesc = deptDesc;
}
public List<Emp> getEmpList() {
return empList;
}
public void setEmpList(List<Emp> empList) {
this.empList = empList;
}
@Override
public String toString() {
return "Dept{" +
"id=" + id +
", deptName='" + deptName + '\'' +
", deptDesc='" + deptDesc + '\'' +
", empList=" + empList +
'}';
}
}
public class Emp {
private Integer id;
private String empName;
private String empAge;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public String getEmpAge() {
return empAge;
}
public void setEmpAge(String empAge) {
this.empAge = empAge;
}
@Override
public String toString() {
return "Emp{" +
"id=" + id +
", empName='" + empName + '\'' +
", empAge='" + empAge + '\'' +
'}';
}
}
(2)在IDeptDao.java中添加方法
Dept selectDeptAndEmp(int id);
(3)在deptMapper.xml中添加sql映射语句,在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">
<!--namespace:指定了唯一的命名空间-->
<mapper namespace="com.day1.dao.IDeptDao">
<resultMap type="com.day1.entity.Dept" id="deptAndEmp">
<id property="id" column="id" />
<result property="deptName" column="dept_name" />
<result property="deptDesc" column="dept_desc" />
<!-- 一对多级联查询,ofType表示集合中的元素类型,将uid传递给selectOrdersByld -->
<collection property="empList" ofType="com.day1.entity.Emp"
column="id" select="com.day1.dao.IEmpDao.selectEmpById" />
</resultMap>
<select id="selectDeptAndEmp" parameterType="int" resultMap="deptAndEmp">
select * from t_dept where id = #{id}
</select>
</mapper>
<?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">
<!--namespace:指定了唯一的命名空间-->
<mapper namespace="com.day1.dao.IEmpDao">
<resultMap type="com.day1.entity.Emp" id="emp">
<id property="id" column="id"/>
<result property="empName" column="emp_name"/>
<result property="empAge" column="emp_age"/>
</resultMap>
<select id="selectEmpById" parameterType="int" resultMap="emp">
select * from t_emp where dept_id = #{id};
</select>
</mapper>
(3)执行测试
@Test
public void testSelect02() throws IOException {
//1、读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapperConfig.xml");
//2、创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3、使用工厂生产SqlSession对象
SqlSession sqlSession = factory.openSession();
//4、使用SqlSession创建dao接口的代理对象
IDeptDao deptDao= sqlSession.getMapper(IDeptDao.class);
//5、使用代理对象执行方案
Dept dept = deptDao.selectDeptAndEmp(2);
System.out.println(dept);
//6、释放资源
sqlSession.close();
in.close();
}
方式二:嵌套结果
<resultMap type="com.day1.entity.Dept" id="deptAndEmp">
<id property="id" column="id" />
<result property="deptName" column="dept_name" />
<result property="deptDesc" column="dept_desc" />
<!-- 一对多级联查询,ofType表示集合中的元素类型,将uid传递给selectOrdersByld -->
<collection property="empList" ofType="com.day1.entity.Emp">
<result property="empName" column="emp_name"/>
<result property="empAge" column="emp_age"/>
</collection>
</resultMap>
<select id="selectDeptAndEmp" parameterType="int" resultMap="deptAndEmp">
select d.*, e.* from t_dept d, t_emp e where d.id=#{id} and d.id=e.dept_id;
</select>
小细节:在collection中并没有对emp的id属性进行映射。这是因为当主表和从表的主键名称相同时,resultMap中如果不定义类似主键之类的能够区分每一条结果集的字段的话,会引起后面一条数据覆盖前面一条数据的现象,从而导致查询结果只有一条数据。
解决办法:
修改主表或者明细表的id名,保证不一致或者给查询结果起别名。
方式三:使用POJO存储结果
创建Dept的扩展类
public class DeptExtend {
private Integer id;
private String deptName;
private String deptDesc;
private String empName;
private String empAge;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getDeptDesc() {
return deptDesc;
}
public void setDeptDesc(String deptDesc) {
this.deptDesc = deptDesc;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public String getEmpAge() {
return empAge;
}
public void setEmpAge(String empAge) {
this.empAge = empAge;
}
@Override
public String toString() {
return "DeptExtend{" +
"id=" + id +
", deptName='" + deptName + '\'' +
", deptDesc='" + deptDesc + '\'' +
", empName='" + empName + '\'' +
", empAge='" + empAge + '\'' +
'}';
}
}
修改sql映射语句
<resultMap type="com.day1.entity.DeptExtend" id="deptExtend">
<id property="id" column="id"/>
<result property="deptName" column="dept_name"/>
<result property="deptDesc" column="dept_desc"/>
<result property="empName" column="emp_name"/>
<result property="empAge" column="emp_age"/>
</resultMap>
<select id="selectDeptAndEmp" parameterType="int" resultMap="deptExtend">
select d.*, e.* from t_dept d, t_emp e where d.id=#{id} and d.id=e.dept_id;
</select>
修改IDeptDao中的方法
List<DeptExtend> selectDeptAndEmp(int id);
修改测试方法
@Test
public void testSelect02() throws IOException {
//1、读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapperConfig.xml");
//2、创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3、使用工厂生产SqlSession对象
SqlSession sqlSession = factory.openSession();
//4、使用SqlSession创建dao接口的代理对象
IDeptDao deptDao= sqlSession.getMapper(IDeptDao.class);
//5、使用代理对象执行方案
List<DeptExtend> deptExtends = deptDao.selectDeptAndEmp(2);
for(DeptExtend dept : deptExtends){
System.out.println(dept);
}
//6、释放资源
sqlSession.close();
in.close();
}
二、多对一查询
多对一查询有两种方式,这里以学生和教师的关系来演示。
方式一:嵌套查询
(1)创建教师表和学生表并插入数据。
CREATE TABLE `t_teacher` (
`tid` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`major` varchar(20) DEFAULT NULL,
PRIMARY KEY (`tid`)
);
insert into t_teacher(name, major) values("张娟","化学");
insert into t_teacher(name, major) values("刘峰","物理");
CREATE TABLE `t_student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) DEFAULT NULL,
`tid` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);
insert into t_student(name, tid) values("张龙", 2);
insert into t_student(name, tid) values("李飞", 2);
insert into t_student(name, tid) values("王刚", 1);
insert into t_student(name, tid) values("张倩", 1);
insert into t_student(name, tid) values("杨玉", 2);
insert into t_student(name, tid) values("刘菲", 2);
(2)创建实体类Student和Teacher
Teacher类:
public class Teacher {
private Integer tid;
private String name;
private String major;
public Integer getTid() {
return tid;
}
public void setTid(Integer tid) {
this.tid = tid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
@Override
public String toString() {
return "Teacher{" +
"tid=" + tid +
", name='" + name + '\'' +
", major='" + major + '\'' +
'}';
}
}
Student类:
public class Student {
private Integer id;
private String name;
private Teacher teacher;
public Integer getId() {
return id;
}
public void setId(Integer 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;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", teacher=" + teacher +
'}';
}
}
(3)创建ITeacherDao和IStudentDao
ITeacherDao:
public interface ITeacherDao {
Teacher findTeacherById(int id);
}
IStudentDao:
public interface IStudentDao {
List<Student> findAll();
}
(4)创建studentMapper.xml和teacherMapper.xml
teacherMapper.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">
<!--namespace:指定了唯一的命名空间-->
<mapper namespace="com.day1.dao.ITeacherDao">
<select id="findTeacherById" parameterType="int" resultType="com.day1.entity.Teacher">
select * from t_teacher where tid = #{tid}
</select>
</mapper>
studentMapper.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">
<!--namespace:指定了唯一的命名空间-->
<mapper namespace="com.day1.dao.IStudentDao">
<select id="findAll" resultMap="studentTeacher">
select * from t_student;
</select>
<!--
思路:
1. 查询所有的学生信息
2.根据查询出来的学生的tid.寻找对应的老师!
-->
<resultMap id="studentTeacher" type="com.day1.entity.Student">
<result property="id" column="id" />
<result property="name" column="name"/>
<!--复杂的属性,我们需要单独处理 对象: association 集合:collection -->
<association property="teacher" column="tid" javaType="com.day1.entity.Teacher" select="com.day1.dao.ITeacherDao.findTeacherById"/>
</resultMap>
</mapper>
(5)SqlMapperConfig中配置
<mapper resource="com/day1/studentMapper.xml"></mapper>
<mapper resource="com/day1/teacherMapper.xml"></mapper>
(6)进行测试。
@Test
public void testSelect() throws IOException {
//1、读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapperConfig.xml");
//2、创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3、使用工厂生产SqlSession对象
SqlSession sqlSession = factory.openSession();
//4、使用SqlSession创建dao接口的代理对象
IStudentDao studentDao= sqlSession.getMapper(IStudentDao.class);
//5、使用代理对象执行方案
List<Student> students = studentDao.findAll();
for(Student stu : students){
System.out.println(stu);
}
//6、释放资源
sqlSession.close();
in.close();
}
方式二:嵌套结果
修改sql映射语句如下:
<select id="findAll" resultMap="studentTeacher">
select stu.id ,stu.name,t.name, t.major
from t_student stu,t_teacher t
where stu.tid = t.tid;
</select>
<resultMap id="studentTeacher" type="com.day1.entity.Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<collection property="teacher" javaType="com.day1.entity.Teacher">
<result property="name" column="name"/>
<result property="major" column="major"/>
</collection>
</resultMap>