案例
一个博客系统中,用户可以任意发表博文(Post),用户还可以对博文进行评论(Comment)。于是在这个系统中,存在以下的关系:
在数据库中,Author,Post和Comment存在于不同的表中。但Comment会使用外键关联Post,而Post又会外键关联Author。
create table author (
id int primary key,
name varchar(20)
);
create table post (
id int primary key,
authorId int,
title varchar(100),
created timestamp,
content text,
foreign key (authorId) REFERENCES author(id)
);
create table comment (
id int primary key,
postId int,
content text,
created timestamp,
foreign key (postId) REFERENCES post(id)
);
在java类中,Author, Post和Comment分别对应的java类型为:
public class Post {
private int id;
private Author author;
private String title;
private String content;
private Timestamp created;
private List<Comment> comments;
// getters and setters
}
public class Author {
private int id;
private String name;
// getters and setters
}
public class Comment {
private int id;
private int postId;
private String content;
private Timestamp created;
// getters and setters
}
下面使用Mybatis的联合查询,创建一个Post实例,其中comments会自动填充到Post的comments表中。
联合查询
首先给出mybatis的配置:
<?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>
<typeAliases>
<typeAlias type="com.test.Post" alias="Post" />
<typeAlias type="com.test.Author" alias="Author" />
<typeAlias type="com.test.Comment" alias="Comment" />
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="jdbc" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/joey" />
<property name="username" value="mysql" />
<property name="password" value="mysql" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/test/my/BlogMapper.xml" />
</mappers>
</configuration>
以及SessionManager工厂类:
public class SessionManager {
private static SqlSessionFactory sessionFactory;
public static synchronized SqlSessionFactory getSessionFactory() {
if (sessionFactory != null) return sessionFactory;
String resource = "com/lux/stat/dest/mybatis-conf.xml";
try {
sessionFactory = new SqlSessionFactoryBuilder().build(Resources
.getResourceAsReader(resource));
} catch (IOException e) {
e.printStackTrace();
}
return sessionFactory;
}
}
还有BlogMapper接口:
public interface BlogMapper {
public Post getPostById(int id);
public List<Post> getPosts();
}
最后是测试用main函数:
public class Test {
public static void main(String[] args) {
// initData();
SqlSession session = SessionManager.getSessionFactory().openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Post post = mapper.getPostById(1);
System.out.println(post.getAuthor().getName());
System.out.println(post.getComments().size());
System.out.println(post.getComments().get(0).getContent());
List<Post> posts = mapper.getPosts();
post=posts.get(0);
System.out.println(post.getAuthor().getName());
System.out.println(post.getComments().size());
System.out.println(post.getComments().get(0).getContent());
session.close();
}
}
Mybatis联合查询提供了两种方式
方式一,嵌套查询
BlogMapper.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="com.test.my.BlogMapper">
<resultMap id="postResult" type="Post">
<association property="author" column="authorId" javaType="Author" select="getAuthorById"/>
<collection property="comments" javaType="ArrayList" column="id" ofType="Comment" select="getCommentsById"/>
</resultMap>
<select id="getPostById" resultMap="postResult">
select id, authorId, title, content, created from post where id=#{param1}
</select>
<select id="getPosts" resultMap="postResult">
select id, authorId, title, content, created from post
</select>
<select id="getAuthorById" resultType="Author">
select id, name from author where id=#{param1}
</select>
<select id="getCommentsById" resultType="Comment">
select id, content, created, postId from comment where postId=#{param1}
</select>
</mapper>
此类方式的缺点是效率低。组合最后的实例,必须要执行多条语句。像本例的getPosts()方法,如果posts数目为n,那么执行sql的条数应该为1+n+n。
方式二,JOIN语句
BlogMapper.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="com.test.my.BlogMapper">
<resultMap id="postResult" type="Post">
<id property="id" column="id" />
<result property="title" column="title" />
<result property="content" column="content" />
<result property="created" column="created" />
<association property="author" javaType="Author">
<id property="id" column="authorId" />
<result property="name" column="name" />
</association>
<collection property="comments" javaType="ArrayList" ofType="Comment">
<id property="id" column="commentId" />
<result property="content" column="comment" />
<result property="created" column="commentCreated" />
</collection>
</resultMap>
<select id="getPosts" resultMap="postResult">
select A.id, A.title, A.content, A.created,
B.id as authorId, B.name,
C.id as commentId, C.content as comment, C.created as commentCreated
from post A
join author B on A.authorid=B.id
join comment C on A.id = C.postId
</select>
<select id="getPostById" resultMap="postResult">
select A.id, A.title, A.content, A.created,
B.id as authorId, B.name,
C.id as commentId, C.content as comment, C.created as commentCreated
from post A
join author B on A.authorid=B.id
join comment C on A.id = C.postId
where A.id=#{param1}
</select>
</mapper>
使用此种方法,可以一条join语句便组装好post实例。