云笔记项目-MyBatis关联映射查询

在云笔记学习过程中,又简单的介绍了MyBatis关联映射查询,以发帖作为例子,开始了对它的学习,不过本文只是查询,不涉及其他类型的数据库操作。由于查询帖子不是简单查询,简单的一一映射将不能满足需求,因此涉及到了复杂查询,需要使用关联查询来解决问题,以下将从数据库结构,配置文件等进行简单说明。

数据库结构

需要建立三张表,P_PERSON,P_POST,P_COMMENT,其中P_PERSON用于保存发帖人的基本信息,P_POST保存发帖内容,并且字段person_id作为外键关联P_PERSON的主键id,最后P_COMMENT用于保存回帖内容,其中字段post_id作为外键关联P_POST的主键id。以下是在Navicat中,三张表的关系图。

建表&数据插入准备

使用Eclipse在云笔记数据库中建立了以上三张表,以下是具体代码:

(1)建立P_PERSON

1 --MyBatis数据自增,MySQL中使用AUTO_INCREMENT,ORACLE中使用SEQUENCE
2 CREATE TABLE P_PERSON(
3       id int not null AUTO_INCREMENT,
4       name VARCHAR(100),
5       PRIMARY KEY(id)
6 );

(2)建立P_POST

1 --为了学习MyBatis关系映射,再建立P_POST表和P_COMMENT表,其中P_POST表保存用户发的帖子,P_COMMENT表保存用户回复的帖子
2 CREATE TABLE P_POST(
3      id int not null AUTO_INCREMENT,
4      title VARCHAR(100),
5      person_id int,
6      PRIMARY KEY(id)     
7 );

(3)建立P_COMMENT

1 CREATE TABLE P_COMMENT(
2     id int not null AUTO_INCREMENT,
3     title VARCHAR(100),
4     post_id int,
5     PRIMARY KEY(id)
6 );

(4)建表完成后创建约束,关联表

--使用P_POST的person_id作为外键,关联P_PERSON的主键id,将两张表关联起来
ALTER TABLE P_POST ADD CONSTRAINT FK_ID FOREIGN KEY(person_id) REFERENCES P_PERSON(id); 

--类似的,关联P_POST和P_COMMENT
ALTER TABLE P_COMMENT ADD CONSTRAINT FK_ID_COMMENT FOREIGN KEY(post_id) REFERENCES P_POST(id);

创建数据表对应实体类+DAO接口

需要建立三个实体类,用于保存数据表对应信息,其中POST实体类不仅仅跟表信息一一对应,还包含person和comments属性,因此需要用到MyBatis关联映射查询。

Person类,对应P_PERSON

package com.boe.Entity;

import java.io.Serializable;

/**
 * 验证MyBatis返回自增类型,数据表对应实体类
*/ public class Person implements Serializable{ private static final long serialVersionUID = 4185328190674358099L; Integer id; //使用包装类,因为数据库中id有null的可能,包装类也可以为null,两者可以一一对应,如果使用基本数据类型将无法表示null String name; //如果查询的结果不完整,使用此构造方法初始化 public Person() { super(); }
public Person(Integer id, String name) { super(); this.id = id; this.name = name; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + "]"; } ...省略Get Set方法 }

Post实体类,对应表P_POST

package com.boe.Entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class Post implements Serializable{
    
    private static final long serialVersionUID = -2929218418809381846L;
    Integer id;
    String title;//帖子内容
    
    //添加人和评论
    Person person;
    List<Comment> comments=new ArrayList<Comment>();//实体内部有集合属性,集合最好初始化,防止空指针异常
    
    
    @Override
    public String toString() {
        return "Post [id=" + id + ", title=" + title + ", person=" + person + ", comments=" + comments + "]";
    }
    
    //如果查询不到person和comment,就调用此构造方法
    public Post() {
        super();
    }


    public Post(Integer id, String title, Person person, List<Comment> comments) {
        super();
        this.id = id;
        this.title = title;
        this.person = person;
        this.comments = comments;
    }

...省略Get Set方法
    
}

实体类Comment对应数据表P_COMMENT

package com.boe.Entity;

import java.io.Serializable;

public class Comment implements Serializable{
    
    private static final long serialVersionUID = -3407225418917489641L;
    Integer id;
    String title;//评论内容
    Integer post_id;
    
    public Comment(Integer id, String title, Integer post_id) {
        super();
        this.id = id;
        this.title = title;
        this.post_id = post_id;
    }


    @Override
    public String toString() {
        return "Comment [id=" + id + ", title=" + title + ", post_id=" + post_id + "]";
    }
        
...省略Get Set方法    

}

DAO接口的话,需要建立一个方法,根据id来查找帖子,帖子内容包含帖子id,帖子内容title,发帖人person和评论内容comments。

 1 package com.boe.Dao;
 2 
 3 import org.springframework.stereotype.Repository;
 4 
 5 import com.boe.Entity.Post;
 6 
 7 @Repository("postDAO")
 8 public interface PostDAO {
 9     
10     //public int addPost(Post post);
11     
12     public Post findPostById(Integer id);
13 
14 }

Mapper文件中创建复杂映射关系

刚开始只查询P_POST表中的字段,但是只有id和title可以直接映射到实体类,person和comments无从得知,但是三张表之间有关联,可以通过查询到的person_id,关联查询PERSON表中的对应信息,通过查询到的id,关联查询P_COMMENT中的title,这样目的就达成了。

其中映射person属性时,其为实体类属性,因此使用association标签,而映射comments属性时,由于其为集合类型属性,因此使用collection标签。

最后查询comment时,再创建了一个单独的查询,其中传入的参数为P_POST表的主键id,不是其他表的,最后查询结果映射到comments属性。

<?xml version="1.0" en评论coding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.boe.Dao.PostDAO">
  
   <!-- 以下查询方法查询不到person,和comment -->
   <!--  
   <select id="findPostById" parameterType="int" resultType="com.boe.Entity.Post">   
     select 
      id,
      title,
      person_id
     from p_post
     where
     id=#{id}         
   </select>
   -->
   
   <!-- 如果需要查询得到person和comment,需要使用resultMap,进行处理 -->
   <select id="findPostById" parameterType="int" resultMap="postMap">   
     select 
       p_post.id,
       title,
       person_id,
       p_person.name
     from p_post
     left outer join p_person on p_person.id=person_id
     where
     p_post.id=#{id}         
   </select>
   
   <resultMap type="com.boe.Entity.Post" id="postMap">
     <!-- 逐一映射每个属性 -->
     <!-- 主键采用id映射,其他采用result映射 -->
     <id column="id" property="id"></id>
     <result column="title" property="title"></result>
     <!-- 映射person属性,由于person是个实体类属性,因此需要用association标签 -->
     <association property="person" javaType="com.boe.Entity.Person">
       <id column="person_id" property="id"></id>
       <result column="name" property="name"></result>
     </association>
     <!-- 映射comments属性,由于comments是一个集合,因此需要使用collection标签 -->
     <collection property="comments" column="id" select="findCommentsByPostId">
       
     </collection>
   </resultMap>
   
   <!-- 查询comments,单独写一个查询 -->
   <select id="findCommentsByPostId" parameterType="int" resultType="com.boe.Entity.Comment">
      select
        id,
        title,
        post_id as postId
      from p_comment      
      where post_id=#{id}
   </select>
     
</mapper>

测试

基于云笔记项目中的测试类,建立单独的测试,测试结果能正常返回帖子详细信息。

 1 package Test;
 2 
 3 import org.junit.Before;
 4 import org.junit.Test;
 5 
 6 import com.boe.Dao.PostDAO;
 7 import com.boe.Entity.Post;
 8 
 9 public class testPost extends baseTest{
10     
11     PostDAO dao;
12     
13     @Before
14     public void initTestPost() {
15         dao=ac.getBean("postDAO",PostDAO.class);
16     }
17     
18     
19     //通过post id来查找帖子
20     @Test
21     public void testFindPost() {
22         Post post=dao.findPostById(1);
23         System.out.println(post);
24     }
25 
26 }

测试结果展示:

结论

(1)当查询结果包含实体类和集合时,简单的一一映射不能满足要求,需要使用MyBatis关联查询,返回类型需要使用resultMap,并在resultMap里逐一配置,映射每个属性。

(2)如果需要映射实体类属性,使用association标签,需要映射集合类型属性,使用collection标签。

原文地址:https://www.cnblogs.com/youngchaolin/p/10795910.html