(五)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作为日志记录。
 
                
            
        
浙公网安备 33010602011771号