(五)Mybatis-多对一和一对多

(五)Mybatis-多对一和一对多

一、多对一查询

1.1、搭建环境

1.1.1 多对一处理

  • 多个学生,对应一个老师

  • 对于学生而言,关联。多个学生,关联一个老师【多对一】

  • 对于老师而言,集合。一个老师,有很多学生【一对多】

1.1.2 搭建数据库环境

创建teacher表

CREATE TABLE `teacher`(
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY(`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

插入一个老师

INSERT INTO teacher(`id`,`name`) VALUES (1,'高老师')

创建student表

create table `student` (
`id` int(10) not null auto_increment,
`name` varchar(10) default null,
`tid` int(10) default null,
primary key (`id`),
key `fktid` (`tid`),
constraint `fktid` foreign key (`tid`) references `teacher` (`id`)
) engine=innodb default charset=utf8

插入5个学生

INSERT INTO `student` VALUES (NULL,'小明','1'),
(NULL,'小高','1')
(NULL,'小张','1')
(NULL,'小王','1')
(NULL,'小李','1')

1.1.3 创建pojo类

导入lombok

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.20</version>
    <scope>provided</scope>
</dependency>

创建Teacher类

package com.happy.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Teacher {
    private int id;
    private String name;
}

创建Student类

package com.happy.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private int id;
    private String name;

//    学生需要关联一个老师
//    private int tid;
    private Teacher teacher;
}

1.1.4 编写mapper接口

一个表对应一个pojo类,对应一个mapper接口

package com.happy.dao;

import com.happy.pojo.Teacher;

import java.util.List;

public interface TeacherMapper {

    List<Teacher> getTeacherList();
}

待扩展,可以方法先不写

package com.happy.dao;

public interface StudentMapper {
}

1.1.5 建立mapper文件(类似接口实现)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.happy.dao.TeacherMapper">

    <select id="getTeacherList" resultType="teacher">
        select *
        from teacher
    </select>

</mapper>

1.1.6 在核心配置文件中注册mapper文件或mapper接口

相当于绑定接口和接口实现mapper文件

1.1.7 测试使用

package com.happy.dao;

import com.happy.pojo.Teacher;
import com.happy.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;

import java.util.List;

public class TeacherMapperTest {
    private static Logger logger = Logger.getLogger(TeacherMapperTest.class);

    @Test
    public void testGetTeacherList() {
        try (SqlSession sqlSession = MybatisUtils.getSqlSession()) {
            TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
            List<Teacher> teacherList = mapper.getTeacherList();
            for (Teacher teacher : teacherList) {
                System.out.println(teacher);
            }
        }
    }
}

1.2 按照查询嵌套处理

1.2.1 原理:类似于子查询

SELECT * FROM student s WHERE s.tid IN (SELECT t.id FROM teacher t)

1.2.2 mapper文件实现

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.happy.dao.StudentMapper">
    <!--    <select id="getStudentsList" resultType="student" >-->
    <!--        SELECT *-->
    <!--        FROM student s-->
    <!--                 LEFT JOIN teacher t ON s.`tid` = t.`id`-->
    <!--    </select>-->

    <!--=========================方式一:按查询嵌套查询=>sub query===========================-->
    <resultMap id="studentMap4SubQuery" type="student">
        <result column="id" property="id"></result>
        <result column="name" property="name"></result>
        <!--        <collection column="tid" property="teacher"></collection>-->
        <!--        如果属性是一个对象,则使用association-->
        <association column="tid" property="teacher" javaType="teacher" select="getTeacherList"></association>

    </resultMap>
    <select id="getStudentsList4SubQuery" resultMap="studentMap4SubQuery">
        SELECT *
        FROM student
    </select>

    <select id="getTeacherList" resultType="teacher">
        select *
        from teacher
        where id = #{tid}
    </select>

<!--============================方式二:按接口嵌套查询=》union===================================-->
    <resultMap id="studentMap4Union" type="student">
        <result column="sid" property="id"></result>
        <result column="sname" property="name"></result>
        <association property="teacher" javaType="teacher">
            <result column="tname" property="name" ></result>
            <result column="tid" property="id"></result>
        </association>
    </resultMap>

    <select id="getStudentsList4Union" resultMap="studentMap4Union">
        select s.id sid, s.name sname, t.name tname,t.id tid
        from student s
                 left join teacher t on s.tid = t.id;
    </select>

</mapper>

1.2.3 测试使用

//方式一
    //按照查询嵌套查询,子查询
    @Test
    public void testGetStudentsList4SubQuery() {
        try (SqlSession sqlSession = MybatisUtils.getSqlSession()) {
            StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
            List<Student> studentList = mapper.getStudentsList4SubQuery();
            for (Student student : studentList) {
                System.out.println(student);
            }
        }
    }

1.3 按照结果嵌套处理

1.3.1 原理:类似于联表查询

SELECT * FROM student s LEFT JOIN teacher t ON s.tid=t.id

1.3.2 mapper文件实现

要注意结果集映射resultMap的时候:

  • 简单类型(8大类+String)用result处理映射
  • 复杂类型(pojo类,map,list等)使用association和collection处理
    • 单一对象使用association
    • 集合类型使用collection
<!--============================方式二:按接口嵌套查询=》union===================================-->
    <resultMap id="studentMap4Union" type="student">
        <result column="sid" property="id"></result>
        <result column="sname" property="name"></result>
        <association property="teacher" javaType="teacher">
            <result column="tname" property="name" ></result>
            <result column="tid" property="id"></result>
        </association>
    </resultMap>

    <select id="getStudentsList4Union" resultMap="studentMap4Union">
        select s.id sid, s.name sname, t.name tname,t.id tid
        from student s
                 left join teacher t on s.tid = t.id;
    </select>

1.3.3 测试使用

 //方式二
    //按照结果嵌套查询,联合查询
    @Test
    public void testGetStudentsList4Union() {
        try (SqlSession sqlSession = MybatisUtils.getSqlSession()) {
            StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
            List<Student> studentList = mapper.getStudentsList4Union();
            for (Student student : studentList) {
                System.out.println(student);
            }
        }
    }

二、一对多处理

2.1 搭建环境

2.1.1 一对多处理

关系同上:

比如:一个老师拥有很多学生!

对老师而言,就是一对多的关系

2.1.2 搭建数据库环境

完全复用上面多对一数据库

2.1.3 创建pojo类

导入lombok

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.20</version>
    <scope>provided</scope>
</dependency>

创建Teacher类

注意这里Teacher里装了很多学生,用集合!

package com.happy.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Teacher {
    private int id;
    private String name;
    private List<Student> studentList;
}

创建Student类

package com.happy.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private int id;
    private String name;
    private int tid;
}

2.1.4 编写mapper接口

编写TeacherMapper

package com.happy.dao;

import com.happy.pojo.Teacher;

import java.util.List;

public interface TeacherMapper {

    List<Teacher> getTeacherList();
}

编写StudentMapper

package com.happy.dao;

import com.happy.pojo.Student;

import java.util.List;

public interface StudentMapper {
    
}

2.1.5 建立mapper文件(类似接口实现)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.happy.dao.TeacherMapper">

    <select id="getTeacherList" resultType="teacher">
        select *
        from teacher
    </select>

</mapper>

2.1.6 在核心配置文件中注册mapper文件或mapper接口

相当于绑定接口和接口实现mapper文件

2.1.7 测试使用

package com.happy.dao;

//import com.happy.dao.UserDaoImpl;

import com.happy.pojo.Student;
import com.happy.pojo.Teacher;
import com.happy.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;

import java.util.List;

public class TeacherMapperTest {
    private static Logger logger = Logger.getLogger(TeacherMapperTest.class);

    @Test
    public void testGetTeacherList() {
        try (SqlSession sqlSession = MybatisUtils.getSqlSession()) {
            TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
            List<Teacher> teacherList = mapper.getTeacherList();
            for (Teacher teacher : teacherList) {
                System.out.println(teacher);
            }
        }
    }
}

可以发现,teacher里的student对象又为空了。现在下面开始解决获取老师即其所有学生。

2.2 按照查询嵌套处理

2.2.1 mapper接口编写

 List<Teacher> getTeacherListBySubQuery();

2.2.2 mapper文件实现

要注意结果集映射resultMap的时候:

  • 简单类型(8大类+String)用result处理映射
  • 复杂类型(pojo类,map,list等)使用association和collection处理
    • 单一对象使用association
    • 集合类型使用collection
    <!--===============================按查询嵌套查询=>子查询==========================================-->
    <resultMap id="TeacherMapBySubQuery" type="teacher">
        <result column="name" property="name"></result>
        <result column="id" property="id"></result>
        <collection property="studentList" ofType="student" select="getStudentList" column="id"></collection>
    </resultMap>

    <select id="getTeacherListBySubQuery" resultMap="TeacherMapBySubQuery">
        select * from teacher;
    </select>

    <select id="getStudentList" resultType="student">
        select * from student where tid=#{tid};
    </select>
</mapper>

2.2.3 测试使用

@Test
    public void testGetTeacherListBySubQuery() {
        try (SqlSession sqlSession = MybatisUtils.getSqlSession()) {
            TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
            List<Teacher> teacherList = mapper.getTeacherListBySubQuery();
            for (Teacher teacher : teacherList) {
                System.out.println(teacher);
            }
        }
    }

2.3 按照结果嵌套处理

2.3.1 mapper接口编写

package com.happy.dao;

import com.happy.pojo.Teacher;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface TeacherMapper {

    List<Teacher> getTeacherList();

    List<Teacher> getTeacherListByUnionQuery();

    Teacher getTeacherById(@Param("tid") int id);
}

2.3.2 mapper文件实现

要注意结果集映射resultMap的时候:

  • 简单类型(8大类+String)用result处理映射
  • 复杂类型(pojo类,map,list等)使用association和collection处理
    • 单一对象使用association
    • 集合类型使用collection
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.happy.dao.TeacherMapper">

    <select id="getTeacherList" resultType="teacher">
        select *
        from teacher
    </select>

    <resultMap id="TeacherMapByUnionQuery" type="teacher">
        <result column="tid" property="id"></result>
        <result column="tname" property="name"></result>
        <collection property="studentList" ofType="student">
            <result column="sname" property="name"></result>
            <result column="sid" property="id"></result>
        </collection>
    </resultMap>

    <select id="getTeacherListByUnionQuery" resultMap="TeacherMapByUnionQuery">
        select t.name tname, t.id tid, s.id sid, s.name sname
        from teacher t
                 left join student s on t.id = s.tid;
    </select>

    <select id="getTeacherById" parameterType="int" resultMap="TeacherMapByUnionQuery">
        select t.name tname, t.id tid, s.id sid, s.name sname
        from teacher t
                 left join student s on t.id = s.tid
        where t.id = #{tid};
    </select>
</mapper>

2.3.3 测试使用

 @Test
    public void testGetTeacherListByUnionQuery() {
        try (SqlSession sqlSession = MybatisUtils.getSqlSession()) {
            TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
            List<Teacher> teacherList = mapper.getTeacherListByUnionQuery();
            for (Teacher teacher : teacherList) {
                System.out.println(teacher);
            }
        }
    }

    @Test
    public void testGetTeacherById() {
        try (SqlSession sqlSession = MybatisUtils.getSqlSession()) {
            TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
            Teacher teacher = mapper.getTeacherById(1);
            System.out.println(teacher);
        }
    }

三、小结

3.1 多对一

  • 关联-association【多对一】

  • association里面使用javaType,指定单一pojo类型

3.2 一对多

teacher包含多个student

  • 集合-collection【一对多】

  • collection里面使用offType,指定集合中类型即泛型类型。

3.3 注意点

  • 保证sql的可读性,尽量保证通俗易懂
  • 注意一对多和多对一种,属性名和和字段的问题。
  • 如果问题不好排查,可以考虑使用log4j作为日志记录。
posted @ 2022-05-02 18:27  高兴518  阅读(99)  评论(0)    收藏  举报