前面已经介绍了简单的MyBatis单表操作,这里来用一个简单的工程来演示下多表关联。
工程创建参考MyBatis(一)单表操作
1.新建三张表(用户表author, 文章表article, 评论表comment)
CREATE TABLE author (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
nickname VARCHAR(255),
birthday DATE,
register_time DATETIME NOT NULL
) default charset=utf8;
CREATE TABLE article (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
author INT NOT NULL,
create_time DATETIME NOT NULL,
modify_time DATETIME NOT NULL,
FOREIGN KEY (author) REFERENCES author (id)
) default charset=utf8;
CREATE TABLE comment (
id INT AUTO_INCREMENT PRIMARY KEY,
author INT NOT NULL,
article INT NOT NULL,
content TINYTEXT NOT NULL,
create_time DATETIME NOT NULL,
FOREIGN KEY (author) REFERENCES author (id),
FOREIGN KEY (article) REFERENCES article (id)
) default charset=utf8;
2.新建三个实体类(Author, Article, Comment)--get,set, 构造方法省略
public class Author {
private int id;
private String username;
private String nickname;
private Date birthday;
private Timestamp registerTime;
}
public class Article {
private int id;
private String title;
private String content;
private Author author;
private List<Comment> comments;
private Timestamp createTime;
private Timestamp modifyTime;
}
public class Comment {
private int id;
private String content;
private Author author;
private Article article;
private Timestamp createTime;
}
3.先看第一种查询操作,第一章我们的例子中表中的列名和实体类中的属性名是一一对应的,所以,查询结果我们就直接用resultType来映射了,但是当列名和属性名不一致的时候,resultType就不行了,所以才有了resultMap来指定每个列名和哪个属性名对应,如下:
<select id="selectAuthor" resultMap="authorResult">
SELECT
id,
username,
nickname,
birthday,
register_time
FROM author
WHERE id = #{id}
</select>
<resultMap id="authorResult" type="Author">
<id property="id" column="id"/>
<result property="registerTime" column="register_time"/>
</resultMap>
上面的例子中:<id>用来映射主键,<result>用来映射一边的属性,如果列名和属性名一样,还可以省略映射关系。比如这里只指定registerTime属性和register_time列名映射。
4. 第二种,多表查询的第一种方式。比如我们要查询某篇文章和对应的作者。先看例子:
<!-- 查询作者 -->
<select id="selectAuthor" resultMap="authorResult">
SELECT
id,
username,
nickname,
birthday,
register_time
FROM author
WHERE id = #{id}
</select>
<resultMap id="authorResult" type="Author">
<id property="id" column="id"/>
<result property="registerTime" column="register_time"/>
</resultMap>
<!-- 查询文章 -->
<select id="selectArticle" resultMap="articleMap">
SELECT
id,
title,
content,
author,
create_time,
modify_time
FROM article
WHERE id = #{id}
</select>
<resultMap id="articleMap" type="Article">
<id property="id" column="id"/>
<result property="createTime" column="create_time"/>
<result property="modifyTime" column="modify_time"/>
<!-- 嵌套查询作者 -->
<association property="author" column="author" select="selectAuthor"/>
</resultMap>
上面的例子中,第一个select查询只是一个简单的单表查询,第二个select查询中也是一个简单的单表查询(看起来是),但是在resultMap中指定了一个association标签,其中就指定着另一个select查询的ID。MyBatis会在每一条查询记录上再执行一次association指定的查询。以此来达到多表关联查询的目的。但是,很显然,当数据量大的时候,这种方式的效率堪忧,因为每执行一次sql语句,我们还要执行一次association指定的查询。所以一般使用下面的查询方式:
5.第三种查询方式。下面的例子中,我们查询某篇文章对应的作者,以及对应的所有评论。
<select id="selectArticleDetails" resultMap="detailedArticleResultMap">
select
A.id as article_id,
A.title as article_title,
A.content as article_content,
A.create_time as article_createTime,
A.modify_time as article_modifyTime,
B.id as author_id,
B.username as author_username,
B.nickname as author_nickname,
B.birthday as author_birthday,
B.register_time as author_registerTime,
C.id as comment_id,
C.content as comment_content,
C.create_time as comment_createTime
from Article A
left outer join Author B on B.id = A.author
left outer join Comment C on A.id = C.article
where A.id = #{id}
</select>
<resultMap id="detailedArticleResultMap" type="Article">
<id property="id" column="article_id"/>
<result property="title" column="article_title"/>
<result property="content" column="article_content"/>
<result property="createTime" column="article_createTime"/>
<result property="modifyTime" column="article_modifyTime"/>
<!-- 指定某些实体类属性对应的类型 -->
<association property="author" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
<result property="nickname" column="author_nickname"/>
<result property="birthday" column="author_birthday"/>
<result property="registerTime" column="author_registerTime"/>
</association>
<!-- 指定集合属性对应的类型 -->
<collection property="comments" ofType="Comment" columnPrefix="comment_">
<id property="id" column="id"/>
<result property="content" column="content"/>
<result property="createTime" column="createTime"/>
</collection>
</resultMap>
单看查询语句来说,这种查询方式和我们平时使用的多表关联查询几乎一模一样,只是在resultMap中需要用association关键字来指定对应的映射,这里association指定的不再是一个select查询的ID,而是resultMap属性。同时用collection关键字指定集合属性对应的类型和resultMap属性。这里columnPrefix用来指定列名的前缀,result中的column就可以直接写成content,而不用写成comment_content了。
最后帮朋友打个小广告