MyBatis 关联映射之多对多

本文通过实例演示了MyBatis如何处理多对多关联映射。首先创建了学生、课程和选课表,然后在Java项目中建立实体类、映射接口和XML配置文件,使用集合的嵌套结果映射方式实现数据关联。最后通过测试类展示了查询和删除多对多关系数据的操作。

我们在这里新建一个数据库并取名 mybatis 用作实验。

创建学生表 tb_student 并插入两条数据:

mysql> create table tb_student(
    -> s_id int primary key auto_increment,
    -> s_name varchar(20),
    -> s_sex varchar(10),
    -> s_age int);

insert into tb_student(s_name,s_sex,s_age) values('Tom','male',18);
insert into tb_student(s_name,s_sex,s_age) values('Jack','male',19);

创建课程表 tb_course 并插入两条数据:

mysql> create table tb_course(
    -> c_id int primary key auto_increment,
    -> c_name varchar(20),
    -> c_credit int);

insert into tb_course(c_name,c_credit) values('Math',5);
insert into tb_course(c_name,c_credit) values('Computer',4);

由于学生和课程是多对多的关联关系,因此创建中间表:选课表 tb_select_course 并插入数据

mysql> create table tb_select_course(
    -> sc_s_id int,
    -> sc_c_id int,
    -> sc_date date,
    -> primary key(sc_s_id,sc_c_id),
    -> foreign key(sc_s_id) references tb_student(s_id),
    -> foreign key(sc_c_id) references tb_course(c_id));

insert into tb_select_course(sc_s_id,sc_c_id,sc_date) values(1,1,'2017-03-01');
insert into tb_select_course(sc_s_id,sc_c_id,sc_date) values(1,2,'2017-03-01');
insert into tb_select_course(sc_s_id,sc_c_id,sc_date) values(2,1,'2017-03-02');
insert into tb_select_course(sc_s_id,sc_c_id,sc_date) values(2,2,'2017-03-02');

检测数据插入情况:

select * from tb_course;
select * from tb_select_course;

4.2 新建项目

按照第二节中的方法新建动态 Web 工程,命名为 ManyToMany。

4.3 导入所需 jar 包

所需 jar 包:

  • MyBatis jar 包: mybatis-3.3.0.jar
  • MySQL 驱动 jar 包: mysql-connector-java-5.1.35.jar
  • 日志记录 jar 包: log4j-1.2.17.jar

将上述的三个 jar 包拷贝到项目的 /WebContent/WEB-INF/lib/ 目录下。

4.4 实体类

在Java Resources/src 的包 shiyanlou.mybatis.manytomany.model 下新建类 Student.java,一个学生具有 id、name、sex、age、courses(List)属性。学生和课程之间是多对多关系,一个学生可以选多门课。

Student.java 的代码如下:

package shiyanlou.mybatis.manytomany.model;

import java.util.List;

public class Student {
    private Integer id;
    private String name;
    private String sex;
    private Integer age;
    private List<Course> courses; 

    public Student() {

    }

    public Student(Integer id, String name, String sex, Integer age,List<Course> courses) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.courses = courses;
    }

    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 String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public List<Course> getCourses() {
        return courses;
    }

    public void setCourses(List<Course> courses) {
        this.courses = courses;
    }

}

再在包 shiyanlou.mybatis.manytomany.model 下新建类 Course.java,一个班级有 id,name,credit、students(List) 属性。课程和学生之间是多对多关系,一个课程可以由多个学生选。

Course.java 的代码如下:

package shiyanlou.mybatis.manytomany.model;

import java.util.List;

public class Course {
    private Integer id;
    private String name;
    private Integer credit;
    private List<Student> students;

    public Course() {

    }

    public Course(Integer id, String name, Integer credit,
            List<Student> students) {
        this.id = id;
        this.name = name;
        this.credit = credit;
        this.students = students;
    }

    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 Integer getCredit() {
        return credit;
    }

    public void setCredit(Integer credit) {
        this.credit = credit;
    }

    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }
}

最后在包 shiyanlou.mybatis.manytomany.model 下新建类 StudentCourseLink.java,用来描述学生和课程之间的关系,其包含

student(Student)、course(Course)、date 属性。

package shiyanlou.mybatis.manytomany.model;

import java.util.Date;

public class StudentCourseLink {
    private Student student;
    private Course course;
    private Date date;

    public StudentCourseLink() {

    }

    public StudentCourseLink(Student student, Course course, Date date) {
        this.student = student;
        this.course = course;
        this.date = date;
    }

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public Course getCourse() {
        return course;
    }

    public void setCourse(Course course) {
        this.course = course;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

}

4.5 创建方法接口和定义映射文件

新建包 shiyanlou.mybatis.manytomany.mapper ,并在包下新建方法接口 StudentMapper.java。

StudentMapper 接口的代码如下:

package shiyanlou.mybatis.manytomany.mapper;

import shiyanlou.mybatis.manytomany.model.Student;
import shiyanlou.mybatis.manytomany.model.StudentCourseLink;

import java.util.List;

public interface StudentMapper {
    /*
     * 查询所有学生及他们的选择课程的信息
     * @return
     * @throws Exception
     */
    public List<Student> selectStudentCourse() throws Exception;

    /*
     * 删除指定id用户的某门课(根据课程id)的选课情况
     * @param StudentCourseLink
     * @throws Exception
     */
    public void deleteStudentCourseById(StudentCourseLink scLink) throws Exception;
}

在包 shiyanlou.mybatis.onetomany.mapper 下新建映射文件 StudentMapper.xml ,映射文件与接口名相同。

StudentMapper.xml 的配置如下:

<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="shiyanlou.mybatis.manytomany.mapper.StudentMapper">
    <!-- 查询所有学生及他们的选择课程的信息 -->
    <select id="selectStudentCourse" resultMap="studentCourseMap">
        select
        s.*,c.* from
        tb_student s,tb_course c,tb_select_course sc
        where s.s_id=sc.sc_s_id
        and c.c_id=sc.sc_c_id
    </select>

    <!-- 根据学生id和课程id删除该学生该门课的选课情况 -->
    <delete id="deleteStudentCourseById" parameterType="StudentCourseLink">  
        delete from tb_select_course where sc_s_id=#{student.id} and sc_c_id=#{course.id}
    </delete> 

    <!-- resultMap:映射实体类和字段之间的一一对应的关系 -->
    <resultMap id="studentCourseMap" type="Student">
        <id property="id" column="s_id" />
        <result property="name" column="s_name" />
        <result property="sex" column="s_sex" />
        <result property="age" column="s_age" />
        <!-- 多对多关联映射:collection -->
        <collection property="courses" ofType="Course">
            <id property="id" column="c_id" />
            <result property="name" column="c_name" />
            <result property="credit" column="c_credit" />
        </collection>
    </resultMap>
</mapper>

在这里,采用的是集合的嵌套结果映射的方式,使用了

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>   
    <!-- 为JavaBean起类别名 -->
    <typeAliases>
        <!-- 指定一个包名起别名,将包内的 Java 类的类名作为类的类别名 -->
        <package name="shiyanlou.mybatis.manytomany.model" />
    </typeAliases>  
       <!-- 配置mybatis运行环境 -->
    <environments default="development">
        <environment id="development">
           <!-- type="JDBC" 代表直接使用 JDBC 的提交和回滚设置 -->
            <transactionManager type="JDBC" />

            <!-- POOLED 表示支持JDBC数据源连接池 -->
            <!-- 数据库连接池,由 Mybatis 管理,数据库名是 mybatis,MySQL 用户名 root,密码为空 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
                <property name="username" value="root" />
                <property name="password" value="" />
            </dataSource>
        </environment>
    </environments> 
    <mappers>
        <!-- 通过 mapper 接口包加载整个包的映射文件 -->
        <package name="shiyanlou/mybatis/manytomany/mapper" />
</mappers>
</configuration>

4.7 日志记录 log4j.properties

使用日志文件是为了查看控制台输出的 SQL 语句。

在项目目录 /Java Resources/src 下新建 MyBatis 日志记录文件

log4j.properties ,在里面添加如下内容:

 # Global logging configuration
log4j.rootLogger=DEBUG, stdout
 # Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

4.8 测试类 Test

在包 shiyanlou.mybatis.manytomany.test 下新建测试类 Test.java ,代码如下:

package shiyanlou.mybatis.manytomany.test;

import shiyanlou.mybatis.manytomany.mapper.StudentMapper;
import shiyanlou.mybatis.manytomany.model.Course;
import shiyanlou.mybatis.manytomany.model.Student;
import shiyanlou.mybatis.manytomany.model.StudentCourseLink;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Test {
    private static SqlSessionFactory sqlSessionFactory;

    public static void main(String[] args) {
        // Mybatis 配置文件
        String resource = "mybatis.cfg.xml";

        // 得到配置文件流
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 创建会话工厂,传入 MyBatis 的配置文件信息
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);


        selectStudentCourse();
        //deleteStudentCourseById();

    }

    // 查询所有学生及他们的选择课程的信息
    private static void selectStudentCourse(){
        // 通过工厂得到 SqlSession
        SqlSession session = sqlSessionFactory.openSession();

        StudentMapper mapper = session.getMapper(StudentMapper.class);
        try {
            List<Student> students = mapper.selectStudentCourse();
            session.commit();
            for(Student stu:students){
                System.out.println(stu.getId()+","+stu.getName()+","+stu.getSex()+","+stu.getAge()+":");
                List<Course> courses = stu.getCourses();
                for(Course cou:courses){
                    System.out.println(cou.getId()+","+cou.getName()+","+cou.getCredit());
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            session.rollback();
        }

        // 释放资源
        session.close();
    }

    // 根据学生id和课程id删除该学生该门课的选课情况
    private static void deleteStudentCourseById(){
        SqlSession session = sqlSessionFactory.openSession();

        StudentMapper mapper = session.getMapper(StudentMapper.class);
        try {
            Student student = new Student();
            student.setId(1);
            Course course = new Course();
            course.setId(2);
            StudentCourseLink scLink = new StudentCourseLink();
            scLink.setStudent(student);
            scLink.setCourse(course);
            mapper.deleteStudentCourseById(scLink);
            session.commit();
        } catch (Exception e) {
            e.printStackTrace();
            session.rollback();
        }

        session.close();
    }
}

4.9 运行测试

运行测试类 Test.java,分别调用 Test 类中的两个方法。

结果如下:

4.9.1 selectStudentCourse()

查询所有学生及他们的选择课程的信息

这里写图片描述

4.9.2 deleteStudentCourseById()

删除 id 为1的学生选择id为2的课程选课情况

这里写图片描述

再次调用 selectStudentCourse() 方法,发现 id 为1的学生已经将 id 为2的课程退选。

这里写图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值