专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

Mybatis一对多、多对一处理

数据库设计

我们用学生和老师的例子来说明:

一对多:一个老师有多个学生,转换为程序设计语言即为一个老师对象下有一个学生对象集合。

多对一:多个学生有同一个老师,学生对象里有一个属性关联着老师。

88_1.png

创建学生、教师表

CREATE TABLE `teacher`(
    `id` int(20) not null,
    `name` VARCHAR(30) DEFAULT NULL,
    PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `teacher`(`id`,`name`) VALUES(1,'hresh');

CREATE TABLE `student`(
    `id` int(20) not null,
    `name` VARCHAR(30) DEFAULT null,
    `tid` int(20) default null,
    PRIMARY KEY (`id`),
    KEY `ftid` (`tid`),
    CONSTRAINT `ftid` FOREIGN KEY (`tid`) REFERENCES `teacher`(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `student`(`id`,`name`,`tid`) VALUES(1,'张三',1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES(2,'李四',1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES(3,'王武',1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES(4,'张散散',1);

多对一处理

1、Student

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

Teacher

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

2、编写 Mapper 接口

StudentMapper.java 定义了两个查询方法,基于不同的实现方式。

public interface StudentMapper {
    List<Student> getStudent();
    List<Student> getStudent2();
}

public interface TeacherMapper {

}

3、编写 Mapper 接口对应的配置文件

关于 StudentMapper.xml 的书写有两种方式。

按查询嵌套处理

<?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.msdn.dao.StudentMapper">

    <select id="getStudent" resultMap="studentTeacher">
        select * from student
    </select>

     <resultMap id="studentTeacher" type="student">
         <id property="id" column="id" />
         <result property="name" column="name" />
         <!--复杂的属性需要单独处理,对象:association;集合:collection-->
         <!--association关联属性  property属性名 javaType属性类型 column在多的一方的表(即学生表)中的列名-->
         <association property="teacher" javaType="Teacher" column="tid" select="getTeacher" />
     </resultMap>

    <!--
       这里传递过来的id,只有一个属性的时候,下面可以写任何值
       association中column多参数配置:
       column="{key=value,key=value}"
       其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的字段名。
   -->
     <select id="getTeacher" resultType="teacher">
         select * from teacher where id = #{tid}
     </select>

</mapper>

关于 getTeacher 查询中的 tid,是随便命名的,如果该查询 SQL 有多个查询条件,则必须一致,如下所示:

<resultMap id="StudentTeacher" type="Student">
    <!--association关联属性  property属性名 javaType属性类型 column在多的一方的表中的列名-->
    <association property="teacher"  column="{id=tid,name=tid}" javaType="Teacher" select="getTeacher"/>
</resultMap>
<!--
这里传递过来的id,只有一个属性的时候,下面可以写任何值
association中column多参数配置:
    column="{key=value,key=value}"
    其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的字段名。
-->
<select id="getTeacher" resultType="teacher">
    select * from teacher where id = #{id} and name = #{name}
</select>

测试代码

    @Test
    public void getStudent(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = studentMapper.getStudent();
        for (Student student : students) {
            System.out.println(student);
        }
        sqlSession.close();
    }

执行结果为:

Student(id=1, name=张三, teacher=Teacher(id=1, name=hresh))
Student(id=2, name=李四, teacher=Teacher(id=1, name=hresh))
Student(id=3, name=王武, teacher=Teacher(id=1, name=hresh))
Student(id=4, name=张散散, teacher=Teacher(id=1, name=hresh))

按结果嵌套处理

StudentMapper.xml

<?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.msdn.dao.StudentMapper">

    <select id="getStudent2" resultMap="studentMap">
        select s.id sid,s.name sname,t.id ttid,t.name tname
        from student s,teacher t
        where s.tid=t.id;
    </select>

    <resultMap id="studentMap" type="student">
        <id property="id" column="sid" />
        <result property="name" column="sname" />
        <!--关联对象property 关联对象在Student实体类中的属性-->
        <association property="teacher" javaType="Teacher" >
            <id property="id" column="ttid" />
            <result property="name" column="tname" />
        </association>
    </resultMap>

</mapper>

测试代码

    @Test
    public void getStudent2(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();

        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = studentMapper.getStudent2();
        for (Student student : students) {
            System.out.println(student);
        }
        sqlSession.close();
    }

上述两种方式的执行效果是一致的,选择哪种方式根据个人理解,觉得哪种简单就使用哪种。

一对多的处理

1、实体类

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

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

2、Mapper 接口

public interface TeacherMapper {

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

3、TeacherMapper.xml

同多对一处理一样,这里也有两种实现方式。

按查询嵌套处理

<?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.msdn.dao.TeacherMapper">

    <select id="getTeacherById2" resultMap="TeacherStudent2">
        select * from mybatis.teacher where id = #{id}
    </select>

    <resultMap id="TeacherStudent2" type="Teacher">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <collection property="students" column="id" javaType="ArrayList" ofType="Student" select="getStudents" />
    </resultMap>

    <select id="getStudents" resultType="Student">
        select * from mybatis.student where tid = #{tid}
    </select>
</mapper>

测试

    @Test
    public void getTeacher(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();

        TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = teacherMapper.getTeacherById2(1);
        System.out.println(teacher);

        sqlSession.close();
    }

执行结果为:

Teacher(id=1, name=hresh, students=[Student(id=1, name=张三, tid=1), Student(id=2, name=李四, tid=1), Student(id=3, name=王武, tid=1), Student(id=4, name=张散散, tid=1)])

按结果嵌套处理

<?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.msdn.dao.TeacherMapper">

    <select id="getTeacherById" resultMap="TeacherStudent">
        select s.id sid,s.name sname,t.id tid,t.name tname
        from mybatis.student s,mybatis.teacher t
        where s.tid = t.id and t.id =#{id}
    </select>

    <resultMap id="TeacherStudent" type="Teacher">
        <id property="id" column="tid" />
        <result property="name" column="tname" />
        <collection property="students" ofType="Student" >
            <result property="id" column="sid" />
            <result property="name" column="sname" />
            <result property="tid" column="tid" />
        </collection>
    </resultMap>

</mapper>

测试

    @Test
    public void getTeacher(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();

        TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = teacherMapper.getTeacherById(1);
        System.out.println(teacher);

        sqlSession.close();
    }

总结

1、 联-association 用于一对一和多对一
2、 集合-collection 用于一对多的关系
3、 JavaType 和 ofType 都是用来指定对象类型的

  • JavaType 是用来指定 pojo 中属性的类型
  • ofType 指定的是映射到 list 集合属性中 pojo 的类型。

参考文献

MyBatis:一对多、多对一处理

Mybatis官网XML映射文件

文章永久链接:https://tech.souyunku.com/18751

未经允许不得转载:搜云库技术团队 » Mybatis一对多、多对一处理

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们