MyBatis(5)多对一、一对多

1.多对一处理

多个对象对应一个对象

例:你们都是我的学生 ,多个学生对应一个老师

掌握两个单词:

  • association — 联系 ,关联 多个人可以关联一个人。
  • collection — 集合 一个人有一个集合,包含多个人。
  • 发现是多对一业务情况,我们需要使用association 标签进行关联

1.1搭建环境

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, '王老师'); 

CREATE TABLE `student` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) 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


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'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '白六', '1');

运行后会在数据库中显示

student表

在这里插入图片描述

teacher表

在这里插入图片描述

创建项目导入数据库

1.2多对一的处理方式一

使用数据库的思想处理:联表查询

1.2.1实体类

Student

package com.kscng.pojo;

public class Student {

    private int id;
    private String name;
    private Teacher teacher;

    public Student() {
    }

    public Student(int id, String name, Teacher teacher) {
        this.id = id;
        this.name = name;
        this.teacher = teacher;
    }

    public int getId() {
        return id;
    }

    public void setId(int 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 +
                '}';
    }
}

Teacher

package com.kscng.pojo;

public class Teacher {
    private int id;
    private String name;

    public Teacher() {
    }

    public Teacher(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}


1.2.2定义dao接口(StudentDao)
List<Student> getStudents();
1.2.3编写查询语句
  1. 查询学生信息 id name tid , 由于我们要得到老师的信息,我们需要联表查询
  2. 查询老师的信息 id name 。

对应的配置文件(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.kscng.dao.StudentDao">

    <!--遇到问题:学生类中关联老师: 多个学生对应一个老师 -->
    <!--<select id="getStudents" resultType="Student">-->
    <!--select s.id,s.name,t.name from mybatis.student as s,mybatis.teacher as t-->
    <!--where s.tid = t.id-->
    <!--</select>-->

    <!--解决问题方式一:按查询结果嵌套处理,模拟数据库思想;-->
    <select id="getStudents" resultMap="StudentTeacher">
        select * from mybatis.student
    </select>
    <resultMap id="StudentTeacher" type="Student">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <!--属性和字段对应  , 类和表对应  , 对象和记录
        关联一个字段
        需求:拿到老师这个类的属性

        association : 关联,多对一
            column : 数据库对应的列名
            property : 对应属性名
            javaType : 多对一字段对应的Java类型
            select : 关联一个语句
        -->
        <association column="tid" property="teacher" javaType="Teacher" select="getTeacher"/>
    </resultMap>

    <select id="getTeacher" resultType="Teacher">
        select * from mybatis.teacher where id = #{id}
    </select>
</mapper>
1.2.4用到的其他资源文件

database.properties文件

driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8
username = root
password = 123456

log4j.properties

### Log4j配置 ###
#定义log4j的输出级别和输出目的地(目的地可以自定义名称,和后面的对应)
#[ level ] , appenderName1 , appenderName2
log4j.rootLogger=DEBUG,console,file

#-----------------------------------#
#1 定义日志输出目的地为控制台
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
####可以灵活地指定日志输出格式,下面一行是指定具体的格式 ###
#%c: 输出日志信息所属的类目,通常就是所在类的全名
#%m: 输出代码中指定的消息,产生的日志具体信息
#%n: 输出一个回车换行符,Windows平台为"/r/n",Unix平台为"/n"输出日志信息换行
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#-----------------------------------#
#2 文件大小到达指定尺寸的时候产生一个新的文件
log4j.appender.file = org.apache.log4j.RollingFileAppender
#日志文件输出目录
log4j.appender.file.File=log/info.log
#定义文件最大大小
log4j.appender.file.MaxFileSize=10mb
###输出日志信息###
#最低级别
log4j.appender.file.Threshold=ERROR
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#-----------------------------------#
#3 druid
log4j.logger.druid.sql=INFO
log4j.logger.druid.sql.DataSource=info
log4j.logger.druid.sql.Connection=info
log4j.logger.druid.sql.Statement=info
log4j.logger.druid.sql.ResultSet=info

#4 mybatis 显示SQL语句部分
log4j.logger.org.mybatis=DEBUG
#log4j.logger.cn.tibet.cas.dao=DEBUG
#log4j.logger.org.mybatis.common.jdbc.SimpleDataSource=DEBUG
#log4j.logger.org.mybatis.common.jdbc.ScriptRunner=DEBUG
#log4j.logger.org.mybatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
#log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

mybatis-config.xml

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

    <!--配置文件修改-->
    <properties resource="database.properties"/>

    <!--Mybatis设置-->
    <settings>
        <!--默认日志实现-->
        <!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
    <!--</settings>-->
        <!--Log4j实现-->
        <setting name="logImpl" value="LOG4J"/>
    </settings>

    <!--配置别名-->
    <typeAliases>
        <!--<typeAlias type="com.kscng.pojo.User" alias="User"/>-->
        <package name="com.kscng.pojo"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!--class对应的是一个接口类-->
        <!--resource对应的是一个接口类的映射文件-->
        <mapper resource="com/kscng/dao/StudentMapper.xml"/>
    </mappers>

</configuration>
1.2.5工具类
package com.kscng.utils;

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

import java.io.IOException;
import java.io.InputStream;

//mybatis的工具类,重复的代码的提纯
public class MyBatisUtils {
    //类变量不需要设置默认值;
    private static SqlSessionFactory sqlSessionFactory;

    static {

        //在maven中,所有的资源文件一般都放在resources目录下,我们可以直接拿到。
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    //设置SqlSessionFactory公共的方法
    public static SqlSessionFactory getSqlSessionFactory(){
        return sqlSessionFactory;
    }

    //获得一个带事务自动提交功能的SqlSession公共的方法
    public static SqlSession getSqlSession(){
        //自动提交事务
        return sqlSessionFactory.openSession(true);
    }

}

1.2.6测试
package com.kscng.dao;

import com.kscng.pojo.Student;
import com.kscng.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class StudentDaoTest {
    @Test
    public void getStudents(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();

        StudentDao mapper = sqlSession.getMapper(StudentDao.class);

        List<Student> students = mapper.getStudents();

        for (Student student : students) {
            System.out.println("学生姓名:"+student.getName()+"\t班主任姓名:"+student.getTeacher().getName());
        }
    }
}
1.2.7结果

在这里插入图片描述

1.2.8 项目结构

在这里插入图片描述

1.3多对一处理方式二

实体类仍使用方式一的

1.3.1编写接口
List<Student> getStudentsTwo();
1.3.2编写处理的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.kscng.dao.StudentDao">

    <!--遇到问题:学生类中关联老师: 多个学生对应一个老师 -->
    <!--<select id="getStudents" resultType="Student">-->
    <!--select s.id,s.name,t.name from mybatis.student as s,mybatis.teacher as t-->
    <!--where s.tid = t.id-->
    <!--</select>-->
    
    <!-- 解决方式二:一个resultMap解决 , 模拟面向对象的思想-->
    <select id="getStudentsTwo" resultMap="StudentTeacher2">
        select s.id,s.name,t.id as tid,t.name as tname
        from mybatis.student as s, mybatis.teacher as t
        where s.tid = t.id
    </select>

    <!--设置结果集映射ResultMap -->
    <resultMap id="StudentTeacher2" type="Student">
        <id property="id" column="id"/>
        <result property="name" column="name"/>

        <!--直接关联一个老师-->
        <association property="teacher" javaType="Teacher">
            <id property="id" column="tid"/>
            <result property="name" column="tname"/>
        </association>
    </resultMap>
</mapper>

其他资源文件不变

1.3.3测试
package com.kscng.dao;

import com.kscng.pojo.Student;
import com.kscng.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class StudentDaoTest {
    @Test
    public void getStudentsTwo(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();

        StudentDao mapper = sqlSession.getMapper(StudentDao.class);

        List<Student> students = mapper.getStudentsTwo();

        for (Student student : students) {
            System.out.println("学生姓名:"+student.getName()+"\t班主任姓名:"+student.getTeacher().getName()
                    +student.getTeacher().getId());
        }

    }

}

1.3.4结果

在这里插入图片描述

1.4总结

  1. mybatis中遇到多对一的情况,要使用关联映射处理:使用association
  2. 两种处理思路:
    1. 数据库思想 : 联表查询
    2. OOP思想 :关联对象

2.一对多处理

一个老师对应多个学生

2.1代码实现

2.1.1实体类

Student

package com.kscng.pojo;

public class Student {
    private int id;
    private String name;
    //多个学生对应一个老师
    private Teacher teacher;

    public Student() {
    }

    public Student(int id, String name, Teacher teacher) {
        this.id = id;
        this.name = name;
        this.teacher = teacher;
    }

    public int getId() {
        return id;
    }

    public void setId(int 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 +
                '}';
    }
}

Teacher

package com.kscng.pojo;

import java.util.List;

public class Teacher {
    private int id;
    private String name;

    //一个老师对应对个学生
    private List<Student> students;

    public Teacher() {
    }

    public Teacher(int id, String name, List<Student> students) {
        this.id = id;
        this.name = name;
        this.students = students;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

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

    @Override
    public String toString() {
        return "Teacher{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", students=" + students +
                '}';
    }
}
2.1.2接口
package com.kscng.dao;

import com.kscng.pojo.Teacher;

public interface TeacherDao {
    //获得一个老师下的所有学生信息; 老师是包含学生的集合;
    //方法一
    Teacher getTeacher(int id);
    //方法二
    Teacher getTeacherTwo(int id);
}

对应的Mapper文件(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.kscng.dao.TeacherDao">

    <!--一对多的处理-->
    <!--面向对象方式解决-->
    <!--方法一-->
    <select id="getTeacher" resultMap="TeacherStudent">
        select s.name sname,s.id sid, t.name tname
        from mybatis.student as s,mybatis.teacher as t
        where s.tid = t.id and t.id = #{id}
    </select>
    <resultMap id="TeacherStudent" type="Teacher">
        <result property="id" column="id"/>
        <result property="name" column="tname"/>
        <collection property="students" ofType="Student">
            <id property="id" column="sid"/>
            <result property="name" column="sname"/>
        </collection>
    </resultMap>
    <!--数据库思想-->
    <!--方法二-->
    <select id="getTeacherTwo" resultMap="TeacherStudent2">
        select * from mybatis.teacher where id = #{id}
    </select>
    <resultMap id="TeacherStudent2" type="Teacher">
        <collection property="students" javaType="ArrayList" ofType="Student" column="id" select="T2"/>
    </resultMap>
    <select id="T2" resultType="Student">
        select * from mybatis.student where tid = #{id}
    </select>
</mapper>
2.1.3工具类
package com.kscng.utils;

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

import java.io.IOException;
import java.io.InputStream;

public class MyBatisUtils {

    //类变量不需要设置默认值;
    private static SqlSessionFactory sqlSessionFactory;

    static {
        //在maven中,所有的资源文件一般都放在resources目录下,我们可以直接拿到。
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //设置SqlSessionFactory公共的方法
    public static SqlSessionFactory getSqlSessionFactory(){
        return sqlSessionFactory;
    }

    //获得一个带事务自动提交功能的SqlSession公共的方法
    public static SqlSession getSqlSession(){
        //自动提交事务
        return sqlSessionFactory.openSession(true);
    }
}

database.properties、log4j.properties不变

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

    <!--配置文件修改-->
    <properties resource="database.properties"/>

    <!--Mybatis设置-->
    <settings>
        <!--默认日志实现-->
        <!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->

        <!--Log4j实现-->
        <setting name="logImpl" value="LOG4J"/>
    </settings>

    <!--配置别名-->
    <typeAliases>
        <!--<typeAlias type="com.kscng.pojo.User" alias="User"/>-->
        <package name="com.kscng.pojo"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!--class对应的是一个接口类-->
        <!--resource对应的是一个接口类的映射文件-->
        <mapper resource="com/kscng/dao/TeacherMapper.xml"/>
    </mappers>

</configuration>
2.1.5 测试类
package com.kscng.dao;

import com.kscng.pojo.Teacher;
import com.kscng.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

public class TeacherDaoTest {
    //方法一
    @Test
    public void getTeacher(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        TeacherDao mapper = sqlSession.getMapper(TeacherDao.class);
        Teacher teacher = mapper.getTeacher(1);

        System.out.println(teacher.getName());
        System.out.println(teacher.getStudents());

    }
//方法二
    @Test
    public void getTeacherTwo(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        TeacherDao mapper = sqlSession.getMapper(TeacherDao.class);
        Teacher teacher = mapper.getTeacherTwo(1);

        System.out.println(teacher.getName());
        System.out.println(teacher.getStudents());
    }
}
2.1.6结果

方法一
在这里插入图片描述
方法二
在这里插入图片描述

2.1.7项目结构

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值