MyBatis表关联 一对多 多对一 多对多
在上一篇文章中,我们已经搭建了eclipse,mybatis,mysql 的开发环境,并且实现了 mybatis 的简单的增删改查功能。参考文章
有了上一篇文章的基础,可以处理一些简单的应用,但在实际项目中,经常是关联表的查询。比如:最常见到的多对一,一对多等。
1. Mybatis表关联一对多
在Java实体对象对中,一对多可以根据List和Set来实现,两者在mybitis中都是通过collection标签来配合来加以实现。这篇介绍的是多表中的多对一表关联查询。
应用场景:首先根据文章 ID 读取一篇文章信息,然后再读取这篇文章的评论。
1.1 准备表和数据
CREATE TABLE `article` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL DEFAULT '',
`content` text,
`created` datetime NOT NULL DEFAULT '2018-09-10 00:00:00',
PRIMARY KEY (`id`)
);
INSERT INTO `article` VALUES ('1', 'MyBatis详解', 'MyBatis详解。。。', '2018-09-10 20:11:23');
CREATE TABLE `comment` (
`cid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`aid` int(10) unsigned NOT NULL,
`commentcontent` varchar(254) NOT NULL DEFAULT '',
`postedby` varchar(20) NOT NULL DEFAULT '',
`created` datetime NOT NULL DEFAULT '2018-09-10 00:00:00',
PRIMARY KEY (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `comment` VALUES ('1', '1', 'MyBatis详解这篇文章写的真好', 'Angelia的头号粉丝', '2018-09-10 21:40:17');
INSERT INTO `comment` VALUES ('2', '1', 'MyBatis详解这篇文章写的简直是太好了', 'Angelia的二号粉丝', '2018-09-10 21:40:17');
INSERT INTO `comment` VALUES ('3', '1', 'MyBatis详解这篇文章写的不能再好了', 'Angelia的三号粉丝', '2018-09-10 21:40:17');
1.2 创建表对应的 JavaBean 对象
public class Article {
private int id;
private String title;
private String content;
private List<Comment> comments;
// getters and setters
}
public class Comment {
private int id;
private String commentcontent;
private String postedBy;
private Article article;
// getters and setters
}
1.3 接口IArticle和映射文件Article.xml
public interface IArticle {
public Article getArticle(int id);
}
<mapper namespace="com.angelia.mybatis.dao.IArticle">
<resultMap id="articleMap" type="Article" >
<id column="id" property="id" />
<!-- <result property="id" column="id" /> -->
<result property="title" column="title" />
<result property="content" column="content" />
</resultMap>
<!-- Article级联评论查询 方法配置 (一篇文章对多个评论) -->
<resultMap id="articleCommentMap" type="Article" extends="articleMap">
<collection property="comments" ofType="com.angelia.mybatis.model.Comment" column="aid">
<id property="id" column="cid" javaType="int" jdbcType="INTEGER" />
<result property="commentcontent" column="commentcontent" javaType="string" jdbcType="VARCHAR" />
<result property="postedBy" column="postedBy" javaType="string" jdbcType="VARCHAR" />
</collection>
</resultMap>
<select id="getArticle" resultMap="articleCommentMap" parameterType="int">
SELECT a.*, c.*
FROM article a, comment c
WHERE a.id = c.aid AND id = #{aid}
</select>
</mapper>
1.4 测试类
@Test
public void test() {
Article article = articleMapper.getArticle(1);
System.out.println("Article: " + article);
List<Comment> comments = article.getComments();
for(Comment comment : comments) {
System.out.println("Comment Content:" + comment.getCommentcontent());
System.out.println("Content Posted By:" + comment.getPostedBy());
}
}
2. Mybatis表关联多对一
在上章的一对多中,我们已经学习如何在 Mybatis 中关联多表,但在实际项目中也是经常使用多对一的情况,在这一节中我们来学习如何处理多对一。多表映射的多对一关系要用到 mybitis 的 association 来加以实现。
应用场景:首先根据帖子 ID 读取一个帖子信息,然后再读取这个帖子所属的用户信息。
2.1 创建接口IComment和映射文件Comment.xml
public interface IComment {
public Comment getComment(int cid);
}
<mapper namespace="com.angelia.mybatis.dao.IComment">
<resultMap id="commentMap" type="Comment">
<id property="id" column="cid" />
<result property="commentcontent" column="commentcontent" />
<result property="postedBy" column="postedBy" />
</resultMap>
<resultMap id="commentArticleMap" type="Comment" extends="commentMap">
<association property="article" javaType="Article">
<id property="id" column="aid" />
<result property="title" column="title" />
<result property="content" column="content" />
</association>
</resultMap>
<!-- <resultMap id="commentArticleMap" type="Comment" >
<result property="id" column="cid" />
<result property="commentcontent" column="commentcontent" />
<result property="postedBy" column="postedBy" />
<association property="article" javaType="Article">
<id property="id" column="aid" />
<result property="title" column="title" />
<result property="content" column="content" />
</association>
</resultMap> -->
<select id="getComment" resultMap="commentArticleMap" parameterType="int">
SELECT a.*, c.*
FROM article a, comment c
WHERE a.id = c.aid AND c.cid = #{cid}
</select>
</mapper>
2.2 测试代码
@Test
public void test() {
Comment comment = commentMapper.getComment(1);
System.out.println("Comment Content:" + comment.getCommentcontent());
System.out.println("Content Posted By:" + comment.getPostedBy());
System.out.println("Article : " + comment.getArticle());
}
3. Mybatis 多对多
Mybatis3.0添加了association和collection标签专门用于对多个相关实体类数据进行级联查询,但仍不支持多个相关实体类数据的级联保存和级联删除操作。因此在进行实体类多对多映射表设计时,需要专门建立一个关联对象类对相关实体类的关联关系进行描述。下文将以“Author”和“Paper”两个实体类之间的多对多关联映射为例进行CRUD操作。
应用场景:假设项目中存在作者和论文,从一个作者读取出它所关联的论文,从一篇论文也知道这篇论文的所有作者信息。
3.1 准备表结构和数据
CREATE TABLE `author` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`author_name` varchar(64) NOT NULL DEFAULT '',
`mobile` varchar(16) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of author
-- ----------------------------
INSERT INTO `author` VALUES ('1', 'Angelia', '13888888888');
INSERT INTO `author` VALUES ('2', 'Snowdrop', '13666666666');
CREATE TABLE `paper` (
`paper_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`paper_title` varchar(100) NOT NULL DEFAULT '',
`paper_content` text,
PRIMARY KEY (`paper_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of paper
-- ----------------------------
INSERT INTO `paper` VALUES ('1', 'MyBatis详解 表关联多对一', '多对一具体详解');
INSERT INTO `paper` VALUES ('2', 'MyBatis详解 表关联一对多', '一对多具体详解');
INSERT INTO `paper` VALUES ('3', 'MyBatis详解 表关联多对多', '多对多具体详解');
CREATE TABLE `author_paper` (
`author_id` int(10) unsigned NOT NULL DEFAULT '0',
`paper_id` int(10) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user_group
-- ----------------------------
INSERT INTO `author_paper` VALUES ('1', '1');
INSERT INTO `author_paper` VALUES ('2', '1');
INSERT INTO `author_paper` VALUES ('1', '2');
INSERT INTO `author_paper` VALUES ('2', '3');
3.2 创建表对应的JavaBean 对象
public class Author {
private int id;
private String authorName;
private String mobile;
private List<Paper> papers;
// getters and setters
}
public class Paper {
private int paperId;
private String title;
private String content;
private List<Author> authors;
// getters and setters
}
public class AuthorPaper {
private int authorId;
private int paperId;
// getters and setters
}
3.3 创建接口和映射文件Author.xml,Paper.xml和AuthorPaper.xml
public interface IAuthor {
public Author getAuthor(int authorId);
public void insertAuthor(Author author);
}
public interface IPaper {
public Paper getPaper(int paperId);
public void insertPaper(Paper paper);
}
public interface IAuthorPaper {
public List<Author> getAuthorsByPaperId(int paperId);
public List<Paper> getPapersByAuthorId(int id);
public void insertAuthorPaper(AuthorPaper authorPaper);
}
<mapper namespace="com.angelia.mybatis.dao.IAuthor">
<parameterMap type="Author" id="parameterAuthorMap">
<parameter property="id"/>
<parameter property="authorName"/>
<parameter property="mobile"/>
</parameterMap>
<insert id="insertAuthor" parameterMap="parameterAuthorMap">
INSERT INTO author(author_name, mobile) VALUES(#{authorName}, #{mobile});
</insert>
<resultMap id="resultAuthorMap" type="Author" >
<result property="id" column="id"/>
<result property="authorName" column="author_name"/>
<result property="mobile" column="mobile"/>
<collection property="papers" column="id" select="com.angelia.mybatis.dao.IAuthorPaper.getPapersByAuthorId"/>
</resultMap>
<select id="getAuthor" resultMap="resultAuthorMap" parameterType="int">
SELECT * FROM author WHERE id = #{id}
</select>
</mapper>
<mapper namespace="com.angelia.mybatis.dao.IPaper">
<parameterMap id="parameterPaperMap" type="Paper">
<parameter property="paperId" />
<parameter property="title" />
<parameter property="content" />
</parameterMap>
<insert id="insertPaper" parameterMap="parameterPaperMap">
INSERT INTO `paper`(paper_title, paper_content) VALUES(#{title}, #{content});
</insert>
<resultMap id="resultPaperMap" type="Paper">
<id property="paperId" column="paper_id" />
<result property="title" column="paper_title" />
<result property="content" column="paper_content" />
<collection property="authors" column="paper_id" select="com.angelia.mybatis.dao.IAuthorPaper.getAuthorsByPaperId" />
</resultMap>
<select id="getPaper" resultMap="resultPaperMap" parameterType="int">
SELECT * FROM `paper` WHERE paper_id = #{paperId}
</select>
</mapper>
<mapper namespace="com.angelia.mybatis.dao.IAuthorPaper">
<parameterMap type="AuthorPaper" id="parameterAuthorPaperMap">
<parameter property="authorId"/>
<parameter property="paperId"/>
</parameterMap>
<insert id="insertAuthorPaper" parameterMap="parameterAuthorPaperMap">
INSERT INTO author_paper(author_id, paper_id) VALUES(#{authorId}, #{paperId})
</insert>
<!-- 根据一篇论文的ID,查看这篇论文的的所有作者 -->
<resultMap id="resultAuthorMap2" type="Author" >
<result property="id" column="id"/>
<result property="authorName" column="author_name"/>
<result property="mobile" column="mobile"/>
</resultMap>
<select id="getAuthorsByPaperId" resultMap="resultAuthorMap2" parameterType="int">
SELECT a.*, ap.paper_id
FROM author a, author_paper ap
WHERE a.id=ap.author_id AND ap.paper_id = #{paperId}
</select>
<!-- 根据一个作者ID,查看这个作者所有论文-->
<resultMap id="resultPaperMap2" type="Paper" >
<result property="paperId" column="paper_id"/>
<result property="title" column="paper_title"/>
<result property="content" column="paper_content"/>
</resultMap>
<select id="getPapersByAuthorId" resultMap="resultPaperMap2" parameterType="int">
SELECT p.*, ap.author_id
FROM paper p, author_paper ap
WHERE p.paper_id = ap.paper_id AND ap.author_id = #{id}
</select>
</mapper>
3.4 创建测试类
public class AuthorPaperTest {
private SqlSession session;
private IAuthorPaper authorPaperMapper;
private IAuthor authorMapper;
private IPaper paperMapper;
@Before
public void before() {
session = MyBatisUtil.getSessionFactory().openSession();
// 获取Mapper
authorPaperMapper = session.getMapper(IAuthorPaper.class);
authorMapper = session.getMapper(IAuthor.class);
paperMapper = session.getMapper(IPaper.class);
}
@After
public void after() {
session.close();
}
@Test
public void test() {
//getAuthorsByPaperId(1);
//getPapersByAuthorId(1);
//getAuthorAndPapers(2);
getAuthorAndPapers(2);
/*Author author = new Author();
author.setAuthorName("优雅的作家Angelia");
author.setMobile("13666666666");
saveAuthor(author);
Paper paper = new Paper();
paper.setTitle("MyBatis从入门到精通");
paper.setContent("MyBatis从入门到精通...");
savePaper(paper);*/
/*AuthorPaper ap = new AuthorPaper();
ap.setAuthorId(4);
ap.setPaperId(4);
saveAuthorPaper(ap);*/
}
public void getAuthorsByPaperId(int paperId) {
List<Author> authors = authorPaperMapper.getAuthorsByPaperId(paperId);
for (Author author : authors) {
System.out.println(author);
}
}
public void getPapersByAuthorId(int id) {
List<Paper> papers = authorPaperMapper.getPapersByAuthorId(id);
for (Paper paper : papers) {
System.out.println(paper);
}
}
public void getPaperAndAuthors(int paperId) {
Paper paper = paperMapper.getPaper(paperId);
System.out.println(paper);
List<Author> authors = paper.getAuthors();
for (Author author : authors) {
System.out.println(author);
}
}
public void getAuthorAndPapers(int authorId) {
Author author = authorMapper.getAuthor(authorId);
System.out.println(author);
List<Paper> papers = author.getPapers();
for (Paper paper : papers) {
System.out.println(paper);
}
}
public void saveAuthorPaper(AuthorPaper authorPaper) {
authorPaperMapper.insertAuthorPaper(authorPaper);
session.commit();
}
public void saveAuthor(Author author) {
authorMapper.insertAuthor(author);
session.commit();
}
public void savePaper(Paper paper) {
paperMapper.insertPaper(paper);
session.commit();
}
}
上一篇: 下拉列表的操作
下一篇: 18.hibernate多对多单向关联