Mybatis多表连接查询

首先在之前建好的数据库mybatis中新建6个表,关系如下(图中没有显示表与表具体的关系,比如一对多,多对多。只是画了箭头,表示有依赖关系)。表blog代表博客,它由某位作者(表author)所写,博客中有很多的文章(表post),每篇文章有零或多条的评论(表comment)和标签(表tag),而表post_tag里面存有文章和标签的id(多对多的关系)。
这里写图片描述

具体的字段描述如下:

这里写图片描述

表中的数据如下:
author

这里写图片描述

blog

这里写图片描述

tag

这里写图片描述

post

这里写图片描述

post_tag

这里写图片描述

comment

这里写图片描述

在项目中新建实体类:
1.Author.java

package cn.edu.cqu.domains;

public class Author {
  private int id;
  private String username;
  private String password;
  private String email;

  public int getId() {
    return id;
  }

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

  public String getUsername() {
    return username;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  public String getEmail() {
    return email;
  }

  public void setEmail(String email) {
    this.email = email;
  }
}

2.Blog.java

package cn.edu.cqu.domains;

import java.util.List;

public class Blog {
  private Integer id;
  private String title;

//  事实上,这个地方的authorId可以不需要了,因为有Author类了。
//  private String authorId;

  //为了连表查询
  private Author author;
  private List<Post> posts;

  public Blog(Integer id) {
    this.id = id;
  }

  public List<Post> getPosts() {
    return posts;
  }

  public void setPosts(List<Post> posts) {
    this.posts = posts;
  }

  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 getAuthorId() {
//    return authorId;
//  }
//
//  public void setAuthorId(String authorId) {
//    this.authorId = authorId;
//  }

  public Author getAuthor() {
    return author;
  }

  public void setAuthor(Author author) {
    this.author = author;
  }
}

3.Tag.java

package cn.edu.cqu.domains;

public class Tag {
  private Integer id;
  private String name;

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

4.PostTag.java:

package cn.edu.cqu.domains;

public class PostTag {
  private Integer id;

//  同上,不需要
//  private Integer postId;
//  private Integer tagId;

  public Integer getId() {
    return id;
  }

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

//  public Integer getPostId() {
//    return postId;
//  }
//
//  public void setPostId(Integer postId) {
//    this.postId = postId;
//  }
//
//  public Integer getTagId() {
//    return tagId;
//  }
//
//  public void setTagId(Integer tagId) {
//    this.tagId = tagId;
//  }
}

5.Post.java

package cn.edu.cqu.domains;

import java.util.List;

public class Post {
  private Integer id;

//  因为类Blog里面有List<Post> posts了。
//  private Integer blogId;
  private String subject;
  private String body;

  //为了连表查询,一篇文章有很多评论,可以有很多标签,故用List存储。
  private Author author;
  private List<Comment> comments;
  private List<Tag> tags;

  public Integer getId() {
    return id;
  }

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

//  public Integer getBlogId() {
//    return blogId;
//  }
//
//  public void setBlogId(Integer blogId) {
//    this.blogId = blogId;
//  }
//

  public String getSubject() {
    return subject;
  }

  public void setSubject(String subject) {
    this.subject = subject;
  }

  public String getBody() {
    return body;
  }

  public void setBody(String body) {
    this.body = body;
  }

  public Author getAuthor() {
    return author;
  }

  public void setAuthor(Author author) {
    this.author = author;
  }

  public List<Comment> getComments() {
    return comments;
  }

  public void setComments(List<Comment> comments) {
    this.comments = comments;
  }

  public List<Tag> getTags() {
    return tags;
  }

  public void setTags(List<Tag> tags) {
    this.tags = tags;
  }
}

6.Comment.java:

package cn.edu.cqu.domains;

public class Comment {
  private Integer id;
//  同上的解释  
//  private Integer postId;
  private String comment;

  public Integer getId() {
    return id;
  }

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

//  public Integer getPostId() {
//    return postId;
//  }
//
//  public void setPostId(Integer postId) {
//    this.postId = postId;
//  }

  public String getComment() {
    return comment;
  }

  public void setComment(String comment) {
    this.comment = comment;
  }
}

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="config.properties">
    </properties>

    <!-- 全局配置参数,需要时再设置 -->
    <!-- 一个配置完整的settings元素的示例如下 -->
    <settings>
        <setting name="cacheEnabled" value="true"/>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="multipleResultSetsEnabled" value="true"/>
        <setting name="useColumnLabel" value="true"/>
        <setting name="useGeneratedKeys" value="false"/>
        <setting name="autoMappingBehavior" value="PARTIAL"/>
        <setting name="defaultExecutorType" value="SIMPLE"/>
        <setting name="defaultStatementTimeout" value="25"/>
        <setting name="defaultFetchSize" value="100"/>
        <setting name="safeRowBoundsEnabled" value="false"/>
        <setting name="localCacheScope" value="SESSION"/>
        <setting name="jdbcTypeForNull" value="OTHER"/>
        <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
    </settings>

    <typeAliases>
        <!-- 类型别名是为Java类型设置一个短的名字。它只和XML配置有关,
        存在的意义仅在于用来减少类完全限定名的冗余 -->
        <!-- 针对单个别名定义 type:类型的路径,类名不能写错,alias:别名 -->
        <typeAlias type="cn.edu.cqu.domains.User" alias="user" />
        <typeAlias type="cn.edu.cqu.domains.Location" alias="location" />

        <!-- 这里就是我们定义的6个类,及其别名 -->
        <typeAlias type="cn.edu.cqu.domains.Author" alias="author" />
        <typeAlias type="cn.edu.cqu.domains.Blog" alias="blog" />
        <typeAlias type="cn.edu.cqu.domains.Post" alias="post" />
        <typeAlias type="cn.edu.cqu.domains.Comment" alias="comment" />
        <typeAlias type="cn.edu.cqu.domains.Tag" alias="tag" />
        <typeAlias type="cn.edu.cqu.domains.PostTag" alias="postTag" />
    </typeAliases>

    <!--尽管可以配置多个环境,每个 SqlSessionFactory 实例只能选择其一。
    每个数据库对应一个 SqlSessionFactory 实例-->
    <!-- 如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器,
    因为 Spring 模块会使用自带的管理器来覆盖前面的配置。 -->
    <environments default="development">
        <environment id="development">
            <!-- JDBC – 这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
            使用jdbc事务管理,事务控制由mybatis -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池,由mybatis管理 -->
            <!--有三种内建的数据源类型(也就是 type=”[UNPOOLED|POOLED|JNDI]”)-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>

    <!-- 映射器 -->
    <mappers>
        <!--通过resource方法一次加载一个映射文件 -->
        <!--注意这里的路径和xml文件 -->
        <mapper resource="mappers/user.xml" />
        <mapper resource="mappers/location.xml" />
        <!--由于实验中只关于blog的查询,故暂时只需要写一个 -->
        <mapper resource="mappers/blog.xml" />
        <!-- 批量加载mapper 指定mapper接口的包名,mybatis自动扫描包下边所有mapper接口进行加载 -->
        <!-- 遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录 -->
        <!-- 中 上边规范的前提是:使用的是mapper代理方法
        <package name="mappers" />-->

    </mappers>

</configuration>

最精彩的部分在blog.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">
<mapper namespace="blog">

    <resultMap id="detailedBlogResultMap" type="Blog">
        <!-- 类Blog中必须要有包含一个参数的构造函数,参数为id,即主键名 -->
        <constructor>
            <idArg column="blog_id" javaType="int"/>
        </constructor>
        <result property="title" column="blog_title"/>
        <!-- 一个博客只属于一个作者,故使用association -->
        <association property="author" javaType="Author">
            <id property="id" column="author_id"/>
            <!-- 获取到用户的用户名,密码,email -->
            <result property="username" column="author_username"/>
            <result property="password" column="author_password"/>
            <result property="email" column="author_email"/>
        </association>
        <!-- 一个博客有很多文章,故使用collection -->
        <collection property="posts" ofType="Post">
            <id property="id" column="post_id"/>
            <!-- 获取到文章的标题和内容 -->
            <result property="subject" column="post_subject"/>
            <result property="body" column="post_body"/>
            <!-- 一篇文章只有一个作者,故使用association -->
            <association property="author" javaType="Author"/>
            <!-- 一篇文章有很多评论,故使用collection -->
            <collection property="comments" ofType="Comment">
                <id property="id" column="comment_id"/>
                <!-- 获取到评论的内容 -->
                <result property="comment" column="comment_text"/>
            </collection>
            <!-- 一篇文章有很多标签,故使用collection -->
            <collection property="tags" ofType="Tag" >
                <id property="id" column="tag_id"/>
                <!-- 获取到标签的内容 -->
                <result property="name" column="tag_name"/>
            </collection>
        </collection>
    </resultMap>

    <select id="selectBlogDetails" resultMap="detailedBlogResultMap">
        select
        B.id as blog_id,
        B.title as blog_title,
        B.author_id as blog_author_id,
        A.id as author_id,
        A.username as author_username,
        A.password as author_password,
        A.email as author_email,
        P.id as post_id,
        P.blog_id as post_blog_id,
        P.subject as post_subject,
        P.body as post_body,
        C.id as comment_id,
        C.post_id as comment_post_id,
        C.comment as comment_text,
        T.id as tag_id,
        T.name as tag_name
        from blog B
        left outer join author A on B.author_id = A.id
        left outer join post P on B.id = P.blog_id
        left outer join comment C on P.id = C.post_id
        left outer join post_tag PT on PT.post_id = P.id
        left outer join tag T on PT.tag_id = T.id
        where B.id = #{id}
    </select>

</mapper>

测试代码如下BlogTest.java

import cn.edu.cqu.domains.*;
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 org.junit.Test;

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

public class BlogTest {

  public SqlSessionFactory getSqlSessionFactory() throws IOException {
    String resource = "mybatis-config.xml";
    // 得到配置文件流
    InputStream inputStream = Resources.getResourceAsStream(resource);
    // 创建会话工厂,传入mybatis的配置文件信息
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    return sqlSessionFactory;
  }

  @Test
  public void selectBlogDetailsTest() throws IOException {
    // 通过工厂得到SqlSession
    SqlSession sqlSession = this.getSqlSessionFactory().openSession();

    //查询博客id为1的博客的所有信息
    Blog blog = sqlSession.selectOne("blog.selectBlogDetails", 1);

    System.out.println("Blog的id为:" + blog.getId());
    System.out.println("Blog的标题为:" + blog.getTitle());
    System.out.println("Blog的作者为:" + blog.getAuthor().getUsername());

    System.out.println("博主的文章如下:");
    for (Post p : blog.getPosts()) {
      System.out.println("------------------------------------------------------------------------");
      //System.out.println("文章id为:" + p.getId());
      System.out.println("|主题:" + p.getSubject());
      System.out.println("|内容:" + p.getBody());
      System.out.print("|标签:" );
      for (Tag tag : p.getTags()) {
        System.out.print(tag.getName() + " ");
      }
      System.out.println();
      System.out.println("|评论:");
      for (Comment c : p.getComments()) {
        System.out.println("|" + c.getComment());
      }
      System.out.println("------------------------------------------------------------------------");
    }

    sqlSession.close();
  }
}

查询结果如下:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qxconverse/article/details/80209630