MyBatis学习总结(八):MyBatis的一对多和多对一查询

一、一对多查询

一对多查询的环境仍基于上一篇,一个部门可以有多个员工,一对多的实现方式也有三种,与一对一查询的方式一致,不同的是一对一查询使用的式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>

猜你喜欢

转载自blog.csdn.net/weixin_47382783/article/details/113837595