MyBatis-09-笔记

Posted 寻7

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis-09-笔记相关的知识,希望对你有一定的参考价值。

MyBatis注解开发多表操作

1 MyBatis的注解实现复杂映射开发

实现复杂关系映射之前我们可以在映射文件中通过配置来实现,使用注解开发后,我们可以使用@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置
在这里插入图片描述
在这里插入图片描述

2 一对一查询

2.1 一对一查询的模型

一对一查询的需求:查询全部用户信息,与此同时查询出该用户对应的身份证信息
(查询所有的身份证对象并查询出所关联的人)

数据准备:

CREATE TABLE person(
 	id INT PRIMARY KEY AUTO_INCREMENT,
 	NAME VARCHAR(20),
 	age INT
 );
 INSERT INTO person VALUES (NULL,'张三',23);
 INSERT INTO person VALUES (NULL,'李四',24);
 INSERT INTO person VALUES (NULL,'王五',25);
 
 CREATE TABLE card(
 	id INT PRIMARY KEY AUTO_INCREMENT,
 	number VARCHAR(30),
 	pid INT,
 	CONSTRAINT cp_fk FOREIGN KEY (pid) REFERENCES person(id)
 );
 INSERT INTO card VALUES (NULL,'12345',1);
 INSERT INTO card VALUES (NULL,'23456',2);
 INSERT INTO card VALUES (NULL,'34567',3);

实体类:

  • Person

    public class Person {
    		    private Integer id;     //主键id
    		    private String name;    //人的姓名
    		    private Integer age;    //人的年龄
    		
    		    public Person() {
    		    }
    		    .......
    }
    
  • Card

    public class Card {
    		    private Integer id;     //主键id
    		    private String number;  //身份证号
    		
    		    private Person p;       //所属人的对象
    		
    		    public Card() {
    		    }
    		    .......
    }
    

2.2 一对一查询的语句

对应的sql语句:

SELECT * FROM card;

SELECT * FROM person WHERE id=#{id};  //之后会发现使用该sql语句是为了使用从card表中查询出来的pid后再从person表中查询数据

2.3 创建PersonMapper接口

public interface PersonMapper {
    //根据id查询
    @Select("SELECT * FROM person WHERE id=#{id}")
    public abstract Person selectById(Integer id);
}

2.4 使用注解配置CardMapper

  • 为什么是先查询card表的数据,再使用pid字段条件查询person表的数据呢?
    • 这是根据具体的开发需求,pid这个外键维持着person表和card表的关系,其实也是可以在person中弄个cid外键关联card主键的,让person中的外键来维护这个一对一的关系。谁来维护关系是根据具体的需求来定,没得需求就随意@_@
    • 下面的CardMapper接口中的注解,就可以简单的理解为,先查询出card表中的所有数据,再根据外键pid去条件查询PersonMapper中对应的person对象,再组装下拼成Card对象的List了,就是这么简简单单@_@
    • 你也可以先查person,再拿person中的id在card中进行条件查询,之后拼接就成Person对象的List,此时Person对象的定义就需要有个属性Card c,这就看你要查询出的是什么List对象了,我感觉这个例子应该描述成查询所有的身份证对象并查询出所关联的人@_@
public interface CardMapper {
    //查询全部
    @Select("SELECT * FROM card")
    @Results({
            @Result(column = "id",property = "id"),
            @Result(column = "number",property = "number"),
            @Result(
                    property = "p",             // 被包含对象的变量名
                    javaType = Person.class,    // 被包含对象的实际数据类型
                    column = "pid",             // 根据查询出的card表中的pid字段来查询person表
                    /*
                        one、@One 一对一固定写法
                        select属性:指定调用哪个接口中的哪个方法
                     */
                    one = @One(select = "com.itheima.one_to_one.PersonMapper.selectById")
            )
    })
    public abstract List<Card> selectAll();
}

2.5 测试类

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.获取CardMapper接口的实现类对象
        CardMapper mapper = sqlSession.getMapper(CardMapper.class);

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

        //6.处理结果
        for (Card card : list) {
            System.out.println(card);
        }

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

}

2.6 一对一配置总结

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

3 一对多查询

3.1 一对多查询的模型

一对多查询的需求:查询全部课程,与此同时查询出该该课程对应的学生信息

CREATE TABLE classes(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20)
);
INSERT INTO classes VALUES (NULL,'一班');
INSERT INTO classes VALUES (NULL,'二班');


CREATE TABLE student(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(30),
	age INT,
	cid INT,
	CONSTRAINT cs_fk FOREIGN KEY (cid) REFERENCES classes(id)
);
INSERT INTO student VALUES (NULL,'张三',23,1);
INSERT INTO student VALUES (NULL,'李四',24,1);
INSERT INTO student VALUES (NULL,'王五',25,2);
INSERT INTO student VALUES (NULL,'赵六',26,2);

实体类:

  • Student

    public class Student {
    	    private Integer id;     //主键id
    	    private String name;    //学生姓名
    	    private Integer age;    //学生年龄
    	
    	    public Student() {
    	    }
    		    .......
    }
    
  • Classes

    public class Classes {
    	    private Integer id;     //主键id
    	    private String name;    //班级名称
    	
    	    private List<Student> students; //班级中所有学生对象
    	
    	    public Classes() {
    	    }
    		    .......
    }
    

3.2 一对多查询的语句

对应的sql语句:

SELECT * FROM classes

SELECT * FROM student WHERE cid=#{cid} //从classes表中查询的id值 对应student中的cid

3.3 创建StudentMapper接口

public interface StudentMapper {
    //根据cid查询student表
    @Select("SELECT * FROM student WHERE cid=#{cid}")
    public abstract List<Student> selectByCid(Integer cid);
}

3.4 使用注解配置ClassesMapper

  • 为什么是先查询Classes表的数据,再使用classes的id字段条件查询Student表的数据呢?
    • 首先应该知道的是多对一和一对多是个相对的概念,多的一方通常叫做从表,而"一"叫做主表,这个关系的维护通常都是从表外键来关联主表的主键@_@
    • 其实这里你细想一下以时可以像一对一那样交换下,先插叙student表,再根据cid条件查询classes表的,当然要在student对象中加一个属性 Classes c的@_@
    • 这里主要是演示一对多查询注解的使用,而具体咋用就看实际需求了@_@
public interface ClassesMapper {
    //查询全部
    @Select("SELECT * FROM classes")
    @Results({
            @Result(column = "id",property = "id"),
            @Result(column = "name",property = "name"),
            @Result(
                    property = "students",  // 被包含对象的变量名
                    javaType = List.class,  // 被包含对象的实际数据类型
                    column = "id",          // 根据查询出的classes表的id字段来查询student表
                    /*
                        many、@Many 一对多查询的固定写法
                        select属性:指定调用哪个接口中的哪个查询方法
                     */
                    many = @Many(select = "com.itheima.one_to_many.StudentMapper.selectByCid")
            )
    })
    public abstract List<Classes> selectAll();
}

3.5 测试类

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.获取ClassesMapper接口的实现类对象
        ClassesMapper mapper = sqlSession.getMapper(ClassesMapper.class);

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

        //6.处理结果
        for (Classes cls : list) {
            System.out.println(cls.getId() + "," + cls.getName());
            List<Student> students = cls.getStudents();
            for (Student student : students) {
                System.out.println("\\t" + student);
            }
        }

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

}

3.6 一对多配置总结

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

4 多对多查询

4.1 多对多查询的模型

多对多查询的需求:查询学生以及所对应的课程信息

CREATE TABLE course(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20)
);
INSERT INTO course VALUES (NULL,'语文');
INSERT INTO course VALUES (NULL,'数学');


CREATE TABLE stu_cr(
	id INT PRIMARY KEY AUTO_INCREMENT,
	sid INT,
	cid INT,
	CONSTRAINT sc_fk1 FOREIGN KEY (sid) REFERENCES student(id),
	CONSTRAINT sc_fk2 FOREIGN KEY (cid) REFERENCES course(id)
);
INSERT INTO stu_cr VALUES (NULL,1,1);
INSERT INTO stu_cr VALUES (NULL,1,2);
INSERT INTO stu_cr VALUES (NULL,2,1);
INSERT INTO stu_cr VALUES (NULL,2,2);

实体类:

  • Student

    public class Student {
    	    private Integer id;     //主键id
    	    private String name;    //学生姓名
    	    private Integer age;    //学生年龄
    	
    		private List<Course> courses;   // 学生所选择的课程集合
    		
    	    public Student() {
    	    }
    		    .......
    }
    
  • Course

    public class Course {
    	    private Integer id;     //主键id
    	    private String name;    //课程名称
    	
    	    public Course() {
    	    }
    		    .......
    }
    

4.2 多对多查询的语句

对应的sql语句:

SELECT DISTINCT s.id,s.name,s.age FROM student s,stu_cr sc WHERE sc.sid=s.id
SELECT c.id,c.name FROM stu_cr sc,course c WHERE sc.cid=c.id AND sc.sid=#{id}//根据学生id查询出所选课程

4.3 创建CourseMapper 接口

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);
}

4.4 使用注解配置StudentMapper

  • 其实你仔细研究这几个案例就能够发现主要就是两个注解@One和@Many
    • 想要查询的对象中包含另一个对象是一个List就用@Many,如果包含的就单单是一个对象就用@One
    • 多对多的关系由一个中间表维护,多对多就可以拆成两个和中间表的一对多
    • 实际的使用就根据具体的需求而定@_@
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(column = "id",property = "id"),
            @Result(column = "name",property = "name"),
            @Result(column = "age",property = "age"),
            @Result(
                    property = "courses",   // 被包含对象的变量名
                    javaType = List.class,  // 被包含对象的实际数据类型
                    column = "id",          // 根据查询出student表的id来作为关联条件,去查询中间表和课程表
                    /*
                        many、@Many 一对多查询的固定写法
                        select属性:指定调用哪个接口中的哪个查询方法
                     */
                    many = @Many(select = "com.itheima.many_to_many.CourseMapper.selectBySid")
            )
    })
    public abstract List<Student> selectAll();
}

4.5 测试类

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();
    }

}

4.6 多对多配置总结

@Results:封装映射关系的父注解。
	Result[] value():定义了 Result 数组
@Result:封装映射关系的子注解。
	column 属性:查询出的表中字段名称
	property 属性:实体对象中的属性名称
	javaType 属性:被包含对象的数据类型
	many 属性:一对多查询固定属性
@Many:一对多查询的注解。
	select 属性:指定调用某个接口

以上是关于MyBatis-09-笔记的主要内容,如果未能解决你的问题,请参考以下文章

[原创]java WEB学习笔记61:Struts2学习之路--通用标签 property,uri,param,set,push,if-else,itertor,sort,date,a标签等(代码片段

sh bash片段 - 这些片段大多只是我自己的笔记;我找到了一些,有些我已经找到了

需要一种有效的方法来避免使用 Laravel 5 重复代码片段

Oracle-常用数据库对象笔记(片段)

如何使用导航组件处理片段内的向上按钮

JSP笔记