mybatis之多表操作

本文详细介绍了MyBatis中的多表模型,包括一对一、一对多和多对多关系的配置。通过XML和注解两种方式展示了多表操作的实现,涉及到的标签如resultMap、association和collection等。此外,还强调了测试方法、注意事项,如配置扫描映射、使用@Select等注解,并提供了相关的实体类、接口和XML配置文件示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多表模型

  1. 一对一:在任意一方建立外键,关联对方的主键。
  2. 一对多:在多的一方建立外键,关联一的一方的主键。
  3. 多对多:借助中间表,中间表至少两个字段,分别关联两张表的主键。

xml方式配置多表操作

使用到的标签及属性说明
  1. 标签及属性说明
    • resultMap标签:配置字段和对象属性的映射关系标签。
      • id属性:定义此映射配置的唯一标识。
      • type属性:设置此映射配置对应的的实体类对象
    • id标签:配置主键映射关系标签。
    • result属性:配置非主键映射关系标签
      • column 属性:表中字段名称
      • property 属性: 实体对象变量名称
    • association属性:配置被包含对象的映射关系标签。(一对一关系时使用此标签)
      • property 属性:被包含对象的变量名
      • javaType 属性:被包含对象的数据类型
    • collection标签:配置被包含对象的映射关系标签(一对多或多对多关系时使用此标签)
      • property 属性:被包含对象的变量名
      • ofType属性:被包含对象的数据类型
一对一

例子:一个学生对应一个身份证号码,一个身份证号码对应一个学生,这就是一对一的关系。

  • 实体类

    //学生实体类
    public class Student {
        private Integer id;     //主键id
        private String name;    //学生姓名
        private Integer age;    //学生年龄
        private Card card;   //学生所对应的身份证信息
        
        //...构造与get、set方法省略
    }
            
    //身份证实体类
    public class Card {
    	private Integer id;     //主键id
    	private String number;  //身份证号
        
    	//...构造与get、set方法省略
    }
            
    
  • 接口

    //关于学生的接口
    public interface StudentMapper {
    
        /**
         * 查询全部学生及其身份证号码
         */
        List<Student> selectAll();
    }
    
  • sql映射文件

    <?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: 设置此xml文件对应的接口的全路径类名-->
    <mapper namespace="com.itheima.one_to_one.StudentMapper">
    
        <!--配置结果映射-->
        <resultMap id="studentMap" type="student">
            <!--配置结果集中的主键字段与实体类中的属性的映射-->
            <id property="id" column="id"/>
            <!--配置结果集中的其他字段与实体类中的属性的映射-->
            <result property="name" column="name"/>
            <result property="age" column="age"/>
            <!--配置一对一的关系映射-->
            <association property="card" javaType="card">
                <id property="id" column="id"/>
                <result property="number" column="number"/>
            </association>
        </resultMap>
    
        <!--
    		查询所有学生信息及其身份证信息
    		id:对应接口中方法名
    		resultMap:表示将此sql语句查询的结果映射到哪里,一般写上自己配置的映射的id
    	-->
        <select id="selectAll" resultMap="studentMap">
            SELECT s.id, s.name, s.age, c.id, c.number FROM student s, card c WHERE s.id=c.pid;
        </select>
    </mapper>
    
一对多

​ 例子:一个班级对应多个学生,一个学生只能对应一个班级,这就是一对多的关系。

  • 实体类

    //学生实体类
    public class Student {
        private Integer id;     //主键id
        private String name;    //学生姓名
        private Integer age;    //学生年龄
        
        //...构造与get、set方法省略
    }
        
    //班级实体类
    public class Classes {
        private Integer id;     //主键id
        private String name;    //班级名称
    
        private List<Student> students; //班级中所有学生对象,一个班级对应多个学生,所以用集合类型
        
         //...构造与get、set方法省略
    }
    
  • 接口

    /**
     * 关于班级的接口
     */
    public interface ClassesMapper {
    
        /**
         * 查询所有班级的记录,以及每个班级下的所有学生
         */
        List<Classes> selectAll();
    }
    
  • 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:设置此xml文件对应的接口-->
    <mapper namespace="com.itheima.one_to_many.ClassesMapper">
    	
        <!--配置结果映射-->
        <resultMap id="classesMap" type="classes">
            <id property="id" column="id"/>
            <result property="name" column="name"/>
            <!--配置一对多的关系映射-->
            <collection property="students" ofType="student">
                <id property="id" column="sid"/>
                <result property="name" column="sname"/>
                <result property="age" column="age"/>
            </collection>
        </resultMap>
    
        <!--查询所有班级的记录,以及每个班级下的所有学生-->
        <select id="selectAll" resultMap="classesMap">
             SELECT c.*, s.id sid, s.name sname, age FROM classes c INNER JOIN student s WHERE c.id=s.cid
        </select>
    </mapper>
    
多对多

​ 例子:一个学生能选择多门课程,一门课程可以被多个学生选择,这就是多对多的关系。

  • 实体类

    //学生实体类
    public class Student {
        private Integer id;     //主键id
        private String name;    //学生姓名
        private Integer age;    //学生年龄
        private List<Course> courses;   //学生所选择的课程对象,多对多的关系用集合类型
        
        //...构造与get、set方法省略
    }
    
    //课程实体类
    public class Course {
        private Integer id;     //主键id
        private String name;    //课程名称
        private List<Student> students;  //选取此课程的学生对象,多对多用集合类型
        
        //...构造与get、set方法省略
    }
    
  • 接口

    /**
     * 关于课程的接口
     */
    public interface CourseMapper {
    
        /**
         * 查询全部课程,以及每门课程所选的学生的记录
         */
        List<Course> selectAll();
    }
    
    
  • 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.itheima.many_to_many.CourseMapper">
    
        <!--配置结果映射-->
        <resultMap id="courseMap" type="course">
            <id property="id" column="cid"/>
            <result property="name" column="cname"/>
            <!--配置关系映射-->
            <!--
                多对多关系使用ofType设置属性对应的类型
                一对一关系使用javaType设置属性对应的类型
            -->
            <collection property="students" ofType="student">
                <id property="id" column="sid"/>
                <result property="name" column="sname"/>
                <result property="age" column="age"/>
            </collection>
        </resultMap>
    
        <!--查询全部课程,以及每门课程所选的学生的记录-->
        <select id="selectAll" resultMap="courseMap">
              SELECT sc.cid, c.name cname, sc.sid, s.name sname, s.age FROM course c
              INNER JOIN stu_cr sc ON c.id=sc.cid
              INNER JOIN student s ON s.id=sc.sid;
        </select>
    </mapper>
    
方法测试

​ 这里只测试一个,其他的方法测试都是一样的步骤.

/**
 * 多对多的测试
 */
public class ManyToManyTest {

    @Test
    public void test01() throws Exception {
        //读取mybatis核心配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        //创建sql会话工厂生成器
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //获取sql会话工厂
        SqlSessionFactory factory = builder.build(inputStream);
        //获取sql会话
        SqlSession sqlSession = factory.openSession(true);
        //获取代理对象
        CourseMapper mapper = sqlSession.getMapper(CourseMapper.class);
        //调用方法
        List<Course> courses = mapper.selectAll();
        //处理结果
        courses.forEach(element -> System.out.println(element));
        //关闭资源
        sqlSession.close();
        inputStream.close();
    }
}
注意
  1. 要导入所需的jar包
  2. mybatis核心配置文件中要进行相应的配置。
  3. 要在mybatis核心配置文件中指定扫描的包或类,这样加载核心配置文件的时候,才能扫描到sql映射配置文件。
<!--配置包扫描-->
<mappers>
    <!--这里直接配置扫描包-->
    <package name="com.itheima"/>
</mappers>

XML配置实现多表查询方式二

在一个xml配置中,调用另一个xml配置中的查询方法。

<!--配置实体类属性和数据库表中列的对应关系-->
<resultMap id="BaseResultMap" type="com.itheima.domain.system.Dept">
    <id column="dept_id" property="id"/>
    <result column="dept_name"  property="deptName"/>
    <result column="parent_id"  property="parentId"/>
    <result column="state" property="state"/>
    <!--
		关联关系
		property:一方中另一方的属性名
		javaType:另一方属性名的数据类型
		column:传递给select属性指定的方法的参数字段。
		select:接下来要调用的方法。
	-->
    <association
                 property="parent"
                 javaType="com.itheima.domain.system.Dept"
                 column="parent_id"
                 select="com.itheima.dao.system.DeptDao.findById"
                 />
</resultMap>

注解的方式实现多表操作

​ 使用注解的方式操作数据库,可以简化我们的代码,并且不需要写slq映射配置文件了。

常用注解介绍
  1. @Select(“查询的 SQL 语句”):执行查询操作注解
  2. @Insert(“新增的 SQL 语句”):执行新增操作注解
  3. @Update(“修改的 SQL 语句”):执行修改操作注解
  4. @Delete(“删除的 SQL 语句”):执行删除操作注解
mybatis注解方式单表操作示例
  • 实体类

    //学生实体类
    public class Student {
        private Integer id;
        private String name;
        private Integer age;
    }
    
  • 接口

    //与学生相关的接口
    
    public interface StudentMapper {
        //查询全部
        @Select("SELECT * FROM student")
        List<Student> selectAll();
    
        //根据id查询
        @Select("SELECT * FROM student WHERE id=#{id}")
        Student selectById(Integer id);
    
        //新增数据
        @Insert("INSERT INTO student VALUES(NULL, #{name}, #{age})")
        Integer insert(Student stu);
    
        //修改数据
        @Update("UPDATE student SET name=#{name}, age=#{age} WHERE id=#{id}")
        Integer update(Student stu);
    
        //删除数据
        @Delete("DELETE FROM student WHERE id=#{id}")
        Integer delete(Integer id);
    }
    
    
  • 测试类

    @Test
    public void test01() throws Exception {
        //读取mybatis核心配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        //创建sql会话工厂生成器
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //获取sql会话工厂
        SqlSessionFactory factory = builder.build(inputStream);
        //获取sql会话
        SqlSession sqlSession = factory.openSession(true);
        //4.获取StudentMapper接口的实现类对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        //5.调用实现类的方法,接收结果
        List<Student> students = mapper.selectAll();
        //6.处理结果
        students.forEach(student -> System.out.println(student));
        //7.释放资源
        sqlSession.close();
        //关闭资源
        sqlSession.close();
        inputStream.close();
    }
    

    这里只测试一个方法,测试其它方法是一样的步骤。

mybatis多表操作常用注解介绍
  • @Results:封装映射关系的父注解。
    • Result[] value():定义了 Result 数组
  • @Result:封装映射关系的子注解。
    • column 属性:查询出的结果集中的字段名称
    • property 属性:要封装的实体对象中的属性名称
    • javaType 属性:被包含对象的数据类型
    • one 属性:一对一查询固定属性
    • many 属性:一对多查询固定属性
  • @One:一对一查询的注解。
    • select 属性:指定调用某个接口中的方法执行。
  • @Many:一对多查询的注解。
    • select 属性:指定调用某个接口中的方法执行。
一对一
  • 实体类

    //人实体类
    public class Person {
       	private Integer id;     //主键id
        private String name;    //人的姓名
        private Integer age;    //人的年龄
        
        //...构造与get、set方法省略
    }
            
    //身份证实体类
    public class Card {
    	private Integer id;     //主键id
        private String number;  //身份证号
        private Person p;       //所属人的对象
        
    	//...构造与get、set方法省略
    }
         
    
  • 接口

    /**
     * 关于人的接口
     */
    public interface PersonMapper {
        //根据id查询
        @Select("SELECT * FROM person WHERE id=#{id}")
        public abstract Person selectById(Integer id);
    }
    
    /**
    * 查询全部身份证信息以及对应的人的信息
    * @return
    */
    @Select("SELECT * FROM card")
    //配置属性与字段映射
    @Results({
        //普通属性与结果集字段配置映射
        @Result(property = "id", column = "id"),
        @Result(property = "number", column = "number"),
        /*
                    配置一对一的映射关系
                    property:被包含对象的属性名
                    javaType:被包含对象的属性对应的数据类型
                    select:要调用执行的方法,指定方法所在类的全限定名+方法名
                    column:执行调用方法所需的参数,值为执行sql语句后的结果集中的字段名
                    one、@One:用于表示一对一的关系
        */
        @Result(property = "p", javaType = Student.class, column = "pid", one = @One(
            select = "com.itheima.one_to_one.PersonMapper.selectById"
        ))
    })
    List<Card> selectAll();
    
一对多
  • 实体类

    //班级实体类
    public class Classes {
        private Integer id;     //主键id
        private String name;    //班级名称
    
        private List<Student> students; //班级中所有学生对象
        
        //...构造与get、set方法省略
    }
    
    //学生实体类
    public class Student {
        private Integer id;     //主键id
        private String name;    //学生姓名
        private Integer age;    //学生年龄
        
        //...构造与get、set方法省略
    }
    
  • 接口

    //关于学生的接口
    public interface StudentMapper {
        //根据cid查询student表
        @Select("SELECT * FROM student WHERE cid=#{cid}")
        public abstract List<Student> selectByCid(Integer cid);
    }
    
    //关于班级的接口
    public interface ClassesMapper {
        //查询全部班级记录及其每个班级下的学生记录
        @Select("SELECT * FROM classes")
        @Results({
                @Result(property = "id", column = "id"),
                @Result(property = "name", column = "name"),
    
                 /*
                    配置一对多的映射关系
                    property:被包含对象的属性名
                    javaType:被包含对象的属性对应的数据类型
                    select:要调用执行的方法,指定方法所在类的全限定名+方法名
                    column:执行调用方法所需的参数,值为执行sql语句后的结果集中的字段名
                    many、@many:用于表示一对多的关系
        		*/
                @Result(property = "students", javaType = List.class, column = "id", many = @Many(
                        select = "com.itheima.one_to_many.StudentMapper.selectByCid"
                ))
        })
        List<Classes> selectAll();
    }
    
    
多对多
  • ​ 实体类

    //学生实体类
    public class Student {
        private Integer id;     //主键id
        private String name;    //学生姓名
        private Integer age;    //学生年龄
    
        private List<Course> courses;   //学生所选择的课程对象
        //...构造与get、set方法省略
    }
    
    //课程实体类
    public class Course {
        private Integer id;     //主键id
        private String name;    //课程名称
        private List<Student> students;  //选取此课程的学生对象,多对多用集合类型
        //...构造与get、set方法省略
    }
    
  • 接口

    //关于课程的接口
    public interface CourseMapper {
        //根据学生id查询所选课程
        @Select("SELECT c.id,c.name FROM stu_cr sc,course c WHERE sc.cid=c.id AND sc.sid=#{id}")
        public abstract List<Course> selectBySid(Integer id);
    }
    
    //关于学生的接口
    public interface StudentMapper {
        //查询全部
        @Select("SELECT DISTINCT s.id,s.name,s.age FROM student s,stu_cr sc WHERE sc.sid=s.id")
        @Results({
                @Result(property = "id", column = "id"),
                @Result(property = "name", column = "name"),
                @Result(property = "age", column = "age"),
                @Result(property = "courses", javaType = List.class, column = "id" , many = @Many(
                        select = "com.itheima.many_to_many.CourseMapper.selectBySid"
                ))
    
        })
        List<Student> selectAll();
    }
    
测试(多对多)
public class Test01 {
    @Test
    public void selectAll() throws Exception{
        //1.加载核心配置文件
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");

        //2.获取SqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

        //3.通过工厂对象获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //4.获取StudentMapper接口的实现类对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        //5.调用实现类对象中的方法,接收结果
        List<Student> list = mapper.selectAll();

        //6.处理结果
        for (Student student : list) {
            System.out.println(student.getId() + "," + student.getName() + "," + student.getAge());
            List<Course> courses = student.getCourses();
            for (Course cours : courses) {
                System.out.println("\t" + cours);
            }
        }

        //7.释放资源
        sqlSession.close();
        is.close();
    }

}

测试方法都大同小异,只是获取代理对象后,调用的方法不同。

注意点

  1. 要记得在mybatis核心配置文件中配置映射扫描

    <!--配置扫描包-->
    <mappers>
        <package name="com.itheima"/>
    </mappers>
    
  2. column是执行sql后的结果集中的字段,当做参数,传递至要调用的方法,作为方法的参数。

     @Result(property = "courses", javaType = List.class, column = "id" , many = @Many(
                        select = "com.itheima.many_to_many.CourseMapper.selectBySid"
     ))
    
  3. 多注意观察报错信息,加油吧 _

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值