Mybatis(三)— 关联查询

关于mybatis环境的搭建,见mybatis环境搭建
关联查询就是多表查询,开发中用得很多

1. 创建数据库中的表和pojo类:

CREATE TABLE `students` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) DEFAULT NULL,
  `sex` varchar(10) DEFAULT NULL,
  `age` int(20) DEFAULT NULL,
  `tel` varchar(15) DEFAULT NULL,
  PRIMARY KEY (`id`)
) 
CREATE TABLE `article` (
  `id` int(12) NOT NULL,
  `title` varchar(20) DEFAULT NULL,
  `content` varchar(30) DEFAULT NULL,
  `student_id` int(12) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=gbk;

建立了两张表,一张是students,一张是article。一个学生可以写很多的文章,但一篇文章只能有一个学生作者。
因此,学生对于文章,是一对多的关系。文章对于学生来说,是一对一的关系。
两张表插入的数据如下:
这里写图片描述
这里写图片描述

对应的pojo类如下

public class Student {
    private Integer id;
    private String name;
    private String sex;
    private Integer age;
    private String tel;
    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 String getTel() {
        return tel;
    }
    public void setTel(String tel) {
        this.tel = tel;
    }
    @Override
    public String toString() {
        return "Student [id=" + id + ", name=" + name + ", sex=" + sex
                + ", age=" + age + ", tel=" + tel + "]";
    }
}
public class Article {
    private Integer id;
    private String title;
    private String content;
    private Integer student_id;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public Integer getStudent_id() {
        return student_id;
    }
    public void setStudent_id(Integer student_id) {
        this.student_id = student_id;
    }
    @Override
    public String toString() {
        return "Article [id=" + id + ", title=" + title + ", content="
                + content + ", student_id=" + student_id + "]";
    }
}

2.一对一查询

通过查询文章信息来查询学生信息,为一对一查询,因为一篇文章只对应一个学生。
一对一查询有两种方式。

2.1 方式一:新创建一个类来描述表结构

查询到的结果是一个类似于笛卡尔乘积的表结构,所以可以新建一个类,来描述这种表结构。

public class StudentArticle {
    //字段为article中的字段
    private Integer id;
    private String title;
    private String content;
    private Integer student_id;
    private String name;
    private String sex;
    private Integer age;
    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 String getTel() {
        return tel;
    }
    public void setTel(String tel) {
        this.tel = tel;
    }
    private String tel;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public Integer getStudent_id() {
        return student_id;
    }
    public void setStudent_id(Integer student_id) {
        this.student_id = student_id;
    }
    @Override
    public String toString() {
        return "StudentArticle [id=" + id + ", title=" + title + ", content="
                + content + ", student_id=" + student_id + ", name=" + name
                + ", sex=" + sex + ", age=" + age + ", tel=" + tel + "]";
    }
}

这个类包括了Student,Article两个类的所有属性。

映射文件associationQuery .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:命名空间,做sql隔离 ,访问sql语句时,sql的id前面要带着命名空间-->
<mapper namespace="assQuery">

<select id="findArticle" resultType="com.mq.pojo.StudentArticle">
    SELECT
    article.*,
    students.name,
    students.age
    FROM
    students,article
    WHERE article.student_id = students.id 
    </select>

</mapper>

测试:

    /**
     * 联合查询,一对一
     */
    @Test
    public void assQuery(){
        SqlSession openSession = factory.openSession();
        List<StudentArticle> list=openSession.selectList("assQuery.findArticle");
        System.out.println(list);
        openSession.close();
    }

结果:

[StudentArticle [id=1, title=学习java, content=内容-java, student_id=1, name=关羽, sex=null, age=42, tel=null], StudentArticle [id=3, title=学习物理, content=内容-物理, student_id=1, name=关羽, sex=null, age=42, tel=null], StudentArticle [id=2, title=数据库, content=内容-数据库, student_id=2, name=刘备, sex=null, age=41, tel=null], StudentArticle [id=3, title=数学, content=内容-数学, student_id=2, name=刘备, sex=null, age=41, tel=null]]
2.2 方式二:使用resultMap

使用resultMap,定义专门的resultMap用于映射一对一查询结果。
每一个Article对应一个Student,所以可以将Student设置为Article的一个属性

修改后的Article(添加了Student 属性):

public class Article {
    private Integer id;
    private String title;
    private String content;
    private Integer student_id;
    //添加了Student属性
    private Student student;
    public Student getStudent() {
        return student;
    }
    public void setStudent(Student student) {
        this.student = student;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public Integer getStudent_id() {
        return student_id;
    }
    public void setStudent_id(Integer student_id) {
        this.student_id = student_id;
    }
    @Override
    public String toString() {
        return "Article [id=" + id + ", title=" + title + ", content="
                + content + ", student_id=" + student_id + ", student="
                + student + "]";
    }
}

修改后的映射文件

<?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:命名空间,做sql隔离 ,访问sql语句时,sql的id前面要带着命名空间-->
<mapper namespace="assQuery">

    <!-- type表示查询结果的类型 -->
    <!--column表示数据库中的字段,property表示pojo类中的属性,通过这种方式将两种字段和属性关联起来  -->
    <resultMap type="com.mq.pojo.Article" id="articleStudentMap">
        <id column="id" property="id"/>
        <result column="title" property="title"/>
        <result column="content" property="content"/>
        <result column="student_id" property="student_id"/>
        <!--如果属性不是基础数据类型,就需要用到association标签,javaType表示该属性的类型,该类的全路径名即可  -->
        <association property="student" javaType="com.mq.pojo.Student">
            <id column="id" property="id"/>
            <result column="name" property="name"/>
            <result column="sex" property="sex"/>
            <result column="age" property="age"/>
            <result column="tel" property="tel"/>
        </association>
    </resultMap>

<select id="findArticle" resultMap="articleStudentMap">
    SELECT
    article.*,
    students.name,
    students.age
    FROM
    students,article
    WHERE article.student_id = students.id 
    </select>

</mapper>

测试:

    /**
     * 联合查询,一对一
     */
        @Test
    public void testResultMap(){
        SqlSession openSession = factory.openSession();
        List<Article> list=openSession.selectList("assQuery.findArticle");
        for (Article article : list) {
            System.out.println("文章名称--"+article.getTitle()+" 作者是--"+article.getStudent().getName());

        }
        openSession.close();
    }

结果:

文章名称--学习java 作者是--关羽
文章名称--学习物理 作者是--关羽
文章名称--数据库 作者是--刘备
文章名称--数学 作者是--刘备

3.一对多查询

查询一个学生写的所有文章,因为一个学生可以写多篇文章,所以为一对多。
修改学生的bean,因为一个学生可以有多篇文章,所以添加一个list属性。

public class Student {
    private Integer id;
    private String name;
    private String sex;
    private Integer age;
    private String tel;
    //学生可以发表多篇文章
    private List<Article> list;
    public List<Article> getList() {
        return list;
    }
    public void setList(List<Article> list) {
        this.list = list;
    }
    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 String getTel() {
        return tel;
    }
    public void setTel(String tel) {
        this.tel = tel;
    }
    @Override
    public String toString() {
        return "Student [id=" + id + ", name=" + name + ", sex=" + sex
                + ", age=" + age + ", tel=" + tel + "]";
    }
}

因为是一对多,所以映射文件也需要修改。
修改后的文件如下

<?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:命名空间,做sql隔离 ,访问sql语句时,sql的id前面要带着命名空间-->
<mapper namespace="yiduiduo">

    <!-- type表示查询结果的类型 -->
    <!--column表示数据库中的字段,property表示pojo类中的属性,通过这种方式将两种字段和属性关联起来  -->
    <resultMap type="com.mq.pojo.Student" id="articleStudentMap">
             <id column="id" property="id"/>
            <result column="name" property="name"/>
            <result column="sex" property="sex"/>
            <result column="age" property="age"/>
            <result column="tel" property="tel"/>
            <!--collection表示该属性为一个集合,ofType表示该集合中的对象的类型  -->
        <collection property="list" ofType="com.mq.pojo.Article">
            <id column="a_id" property="id"/>
            <result column="title" property="title"/>
            <result column="content" property="content"/>
            <result column="student_id" property="student_id"/>
        </collection>
    </resultMap>


<select id="findStudent" resultMap="articleStudentMap">
    SELECT
    students.*,
    article.title,
    article.content,
    article.id a_id
    FROM
    students left join article
    on article.student_id = students.id 
    </select>
</mapper>

测试:

    @Test
    public void yiduiduo(){
        SqlSession openSession = factory.openSession();
        List<Student> list=openSession.selectList("yiduiduo.findStudent");
        for (Student student : list) {
            System.out.println(student.getName()+"写的文章个数是"+student.getList().size());
        }

        openSession.close();

    }
一对多表查询注意事项:

两张表的查询结果一定不能出现相同的字段,如果有,需要使用别名加以区分;查询语句中的字段,在映射关系中一定要有。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值