前言

在对数据库进行查询时,我们会遇到各种各样的查询需求,比如多表联结查询,这就需要了解一对一、一对多、多对多等概念。一对一顾名思义就是一个对象对应一个对象,比如一个班主任对应一个班级,这就是一对一,那么一对多可以理解为一个班级对应多个学生,在面向对象设计实体属性里就是班级类包含学生集合。下面用我的漫画查询作为例子来介绍这两种的关系。

例子

主要介绍的是一对多。在一部漫画中,通常关系都是这样的,一部漫画有多个章节,一个章节有多张图片,即是漫画:章节=1:n,漫画章节:章节图片=1:n。因此,在查询一部漫画所有内容时候我们可以通过先查漫画id获得漫画简介信息,然后通过漫画id获得章节列表,再根据每一个章节的id获得每一章的图片集合。下面分别使用了xml映射文件形式和注解形式实现这种关联查询方法。

首先要看看每个的实体类,不难发现都是一对多的关系

@Data
public class Message {
private Integer comicId;
private String comicName;
private List<ChapterModel> chapterList;
}

@Data
public class ChapterModel {
private Integer chapterId;
private String chapterName;
private List<String> picList;
}

映射文件形式
这种形式我使用了左外连接的sql写法,在两个连接关节都让左表作为主表来列出所有集合元素

<!--总信息-->
<resultMap id="message" type="com.example.kbcomic.model.Message">
<result property="comicId" column="comic_id"></result>
<result property="comicName" column="comic_name"></result>
<!--章节集合-->
<collection property="chapterList" ofType="com.example.kbcomic.model.ChapterModel">
<result column="chapter_id" property="chapterId"></result>
<result column="chapter_name" property="chapterName"></result>
<!--图片集合-->
<collection property="picList" ofType="java.lang.String">
<result column="pic_url" property="picUrl"></result>
</collection>
</collection>
</resultMap>
<!--查询总信息-->
<select id="queryMessageByComicId" resultMap="message" parameterType="java.lang.Integer">
select
all_comic.comic_id,
all_comic.comic_name,
all_chapter.chapter_id,
all_chapter.chapter_name,
all_pic.pic_url
from
all_comic
left join all_chapter on all_comic.comic_id=all_chapter.comic_id
left join all_pic on all_chapter.chapter_id=all_pic.chapter_id
where all_comic.comic_id=#{id}
</select>

注解写法
这种方式其实是对数据库查了三次再拼接起来最后的集合

/**
* 注解方式实现一对多
*/
@Select("select comic_id,comic_name from all_comic where comic_id=#{id}")
@Results({
@Result(column = "comic_id",property = "comicId"),
@Result(column = "comic_name",property = "comicName"),
@Result(property = "chapterList",column = "comic_id",
many = @Many(select = "com.example.kbcomic.mapper.MessageMapper.queryChapterList"))
})
Message queryMessage(@Param("id")Integer comicId);

//根据漫画id查所有章节
@Select("select chapter_id,chapter_name from all_chapter where comic_id=#{comic_id}")
@Results({
@Result(column = "chapter_id",property = "chapterId"),
@Result(column = "chapter_name",property = "chapterName"),
@Result(property = "picList",column = "chapter_id",
many = @Many(select = "com.example.kbcomic.mapper.MessageMapper.queryPicList"))
})
List<ChapterModel>queryChapterList(@Param("comic_id")Integer id);

//根据章节id查所有图片
@Select("select pic_url from all_pic where chapter_id=#{chapter_id}")
List<String>queryPicList(@Param("chapter_id")Integer id);

这两种写法得到的结果都是一样的。

相关注释与标签的理解

在上面的例子中,主要有两个关键的注释或标签:@Many<collection>。这两个分别在注解方式和xml映射文件中使用,意思是一样的。@Manyselect属性指向的是合适类型集合的映射语句。如果在该映射语句中需要参数,则要通过同一级的@Result标签中的column属性指定并传递。而一对一的关系则需要用@One<association>,其用法跟一对多一样。