映射
- 低价出售流量10000IP只需8元
- 30余款阿里云产品免费6个月>>
- 日供百万IP、2亿UV★5元/万、可点击
- 1G香港云49元/美国云49元/韩国云89元
- 大米云主机618不止4折,1元当作61.8花
- ◆◆◆海西数据全球服务器租用◆◆◆
- ★免费虚拟定位软件,安卓苹果都可以用★
- 中原地区核心数据中心,首月托管免费
- 【3000个备案老域名】100元起 每天更新
- ◆◆◆◆◆高防免备案CDN◆◆◆◆◆
- BGP四线 亿恩1U服务器托管3999元/年
- 九九数据 — 工信部认可正规资质IDC接入商
- OO搜索 PHP PYTHON JQUERY 免费收录网站
- 百兆 12核24线程 16G内存 2T 999/月
- 众生网络 基于云计算的互联网基础服务运营商
- 拔号VPS/全国混拔VPS/拔号服务器-创梦网络
- 枫信科技-江苏双线10M保证-399/元
- 港湾网络-徐州百独16核32G 999/月~
- 免备vps20/百独799/双线350/45互联
- 韩国香港美国站群服务器 巨牛网络
- 鼎点网络百兆独享服务器仅需999元
- [香港双高防]无视CC★DDOS/堪比广东!
- 畅游网络 百独服务器 包跑满 998元
- 服务器租用 199元起
- █▇▆5M独享云主机599/年▆▇█
- 群英云服务器送10M带宽30G防御,49元起
- 服务器租用/托管-域名空间/认准腾佑科技
- ▆▇██香港云虚拟主机¥1/年 ▆▇█
mybatis 提供了高级的关联查询功能,可以很方便地将数据库获取的结果集映射到定义的Java Bean 中。下面通过一个实例,来展示一下Mybatis对于常见的一对多和多对一关系复杂映射是怎样处理的。
设计一个简单的博客系统,一个用户可以开多个博客,在博客中可以发表文章,允许发表评论,可以为文章加标签。博客系统主要有以下几张表构成:
Author表:作者信息表,记录作者的信息,用户名和密码,邮箱等。
Blog表 : 博客表,一个作者可以开多个博客,即Author和Blog的关系是一对多。
Post表 : 文章记录表,记录文章发表时间,标题,正文等信息;一个博客下可以有很多篇文章,Blog 和Post的关系是一对多。
Comments表:文章评论表,记录文章的评论,一篇文章可以有很多个评论:Post和Comments的对应关系是一对多。
Tag表:标签表,表示文章的标签分类,一篇文章可以有多个标签,而一个标签可以应用到不同的文章上,所以Tag和Post的关系是多对多的关系;(Tag和Post的多对多关系通过Post_Tag表体现)
Post_Tag表: 记录 文章和标签的对应关系。
一般情况下,我们会根据每一张表的结构 创建与此相对应的JavaBean(或者Pojo),来完成对表的基本CRUD操作。
上述对单个表的JavaBean定义有时候不能满足业务上的需求。在业务上,一个Blog对象应该有其作者的信息和一个文章列表,如下图所示:
如果想得到这样的类的实例,则最起码要有一下几步:
1. 通过Blog 的id 到Blog表里查询Blog信息,将查询到的blogId 和title 赋到Blog对象内;
2. 根据查询到到blog信息中的authorId 去 Author表获取对应的author信息,获取Author对象,然后赋到Blog对象内;
3. 根据 blogId 去 Post表里查询 对应的 Post文章列表,将List<Post>对象赋到Blog对象中;
这样的话,在底层最起码调用三次查询语句,请看下列的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/*
*
通过blogId获取BlogInfo对象
*/
public
static
BlogInfo ordinaryQueryOnTest(String blogId)
{
BigDecimal
id = new
BigDecimal(blogId);
SqlSession
session = sqlSessionFactory.openSession();
BlogInfo
blogInfo = new
BlogInfo();
//1.根据blogid
查询Blog对象,将值设置到blogInfo中
Blog
blog = (Blog)session.selectOne( "com.foo.bean.BlogMapper.selectByPrimaryKey" ,id);
blogInfo.setBlogId(blog.getBlogId());
blogInfo.setTitle(blog.getTitle());
//2.根据Blog中的authorId,进入数据库查询Author信息,将结果设置到blogInfo对象中
Author
author = (Author)session.selectOne( "com.foo.bean.AuthorMapper.selectByPrimaryKey" ,blog.getAuthorId());
blogInfo.setAuthor(author);
//3.查询posts对象,设置进blogInfo中
List
posts = session.selectList( "com.foo.bean.PostMapper.selectByBlogId" ,blog.getBlogId());
blogInfo.setPosts(posts);
//以JSON字符串的形式将对象打印出来
JSONObject
object = new
JSONObject(blogInfo);
System.out.println(object.toString());
return
blogInfo;
}
|
从上面的代码可以看出,想获取一个BlogInfo对象比较麻烦,总共要调用三次数据库查询,得到需要的信息,然后再组装BlogInfo对象。
嵌套语句查询
mybatis提供了一种机制,叫做嵌套语句查询,可以大大简化上述的操作,加入配置及代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
< resultMap
type = "com.foo.bean.BlogInfo"
id = "BlogInfo" >
< id
column = "blog_id"
property = "blogId"
/>
< result
column = "title"
property = "title"
/>
< association
property = "author"
column = "blog_author_id"
javaType = "com.foo.bean.Author"
select = "com.foo.bean.AuthorMapper.selectByPrimaryKey" >
</ association >
< collection
property = "posts"
column = "blog_id"
ofType = "com.foo.bean.Post"
select = "com.foo.bean.PostMapper.selectByBlogId" >
</ collection >
</ resultMap >
< select
id = "queryBlogInfoById"
resultMap = "BlogInfo"
parameterType = "java.math.BigDecimal" >
SELECT
B.BLOG_ID,
B.TITLE,
B.AUTHOR_ID
AS BLOG_AUTHOR_ID
FROM
LOULUAN.BLOG B
where
B.BLOG_ID = #{blogId,jdbcType=DECIMAL}
</ select >
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/*
*
通过blogId获取BlogInfo对象
*/
public
static
BlogInfo nestedQueryOnTest(String blogId)
{
BigDecimal
id = new
BigDecimal(blogId);
SqlSession
session = sqlSessionFactory.openSession();
BlogInfo
blogInfo = new
BlogInfo();
blogInfo
= (BlogInfo)session.selectOne( "com.foo.bean.BlogMapper.queryBlogInfoById" ,id);
JSONObject
object = new
JSONObject(blogInfo);
System.out.println(object.toString());
return
blogInfo;
}
|
通过上述的代码完全可以实现前面的那个查询。这里我们在代码里只需要 blogInfo = (BlogInfo)session.selectOne("com.foo.bean.BlogMapper.queryBlogInfoById",id);一句即可获取到复杂的blogInfo对象。
嵌套语句查询的原理
在上面的代码中,Mybatis会执行以下流程:
1.先执行 queryBlogInfoById 对应的语句从Blog表里获取到ResultSet结果集;
2.取出ResultSet下一条有效记录,然后根据resultMap定义的映射规格,通过这条记录的数据来构建对应的一个BlogInfo 对象。
3. 当要对BlogInfo中的author属性进行赋值的时候,发现有一个关联的查询,此时Mybatis会先执行这个select查询语句,得到返回的结果,将结果设置到BlogInfo的author属性上;
4. 对BlogInfo的posts进行赋值时,也有上述类似的过程。
5. 重复2步骤,直至ResultSet. next () == false;
以下是blogInfo对象构造赋值过程示意图:
这种关联的嵌套查询,有一个非常好的作用就是:可以重用select语句,通过简单的select语句之间的组合来构造复杂的对象。上面嵌套的两个select语句com.foo.bean.AuthorMapper.selectByPrimaryKey和com.foo.bean.PostMapper.selectByBlogId完全可以独立使用。
N+1问题
它的弊端也比较明显:即所谓的N+1问题。关联的嵌套查询显示得到一个结果集,然后根据这个结果集的每一条记录进行关联查询。
现在假设嵌套查询就一个(即resultMap 内部就一个association标签),现查询的结果集返回条数为N,那么关联查询语句将会被执行N次,加上自身返回结果集查询1次,共需要访问数据库N+1次。如果N比较大的话,这样的数据库访问消耗是非常大的!所以使用这种嵌套语句查询的使用者一定要考虑慎重考虑,确保N值不会很大。
以上面的例子为例,select 语句本身会返回com.foo.bean.BlogMapper.queryBlogInfoById 条数为1 的结果集,由于它有两条关联的语句查询,它需要共访问数据库 1*(1+1)=3次数据库。
嵌套结果查询
嵌套语句的查询会导致数据库访问次数不定,进而有可能影响到性能。Mybatis还支持一种嵌套结果的查询:即对于一对多,多对多,多对一的情况的查询,Mybatis通过联合查询,将结果从数据库内一次性查出来,然后根据其一对多,多对一,多对多的关系和ResultMap中的配置,进行结果的转换,构建需要的对象。
重新定义BlogInfo的结果映射 resultMap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
< resultMap
type = "com.foo.bean.BlogInfo"
id = "BlogInfo" >
< id
column = "blog_id"
property = "blogId" />
< result
column = "title"
property = "title" />
< association
property = "author"
column = "blog_author_id"
javaType = "com.foo.bean.Author" >
< id
column = "author_id"
property = "authorId" />
< result
column = "user_name"
property = "userName" />
< result
column = "password"
property = "password" />
< result
column = "email"
property = "email" />
< result
column = "biography"
property = "biography" />
</ association >
< collection
property = "posts"
column = "blog_post_id"
ofType = "com.foo.bean.Post" >
< id
column = "post_id"
property = "postId" />
< result
column = "blog_id"
property = "blogId" />
< result
column = "create_time"
property = "createTime" />
< result
column = "subject"
property = "subject" />
< result
column = "body"
property = "body" />
< result
column = "draft"
property = "draft" />
</ collection >
</ resultMap >
|
对应的sql语句如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
< select
id = "queryAllBlogInfo"
resultMap = "BlogInfo" >
SELECT
B.BLOG_ID,
B.TITLE,
B.AUTHOR_ID
AS BLOG_AUTHOR_ID,
A.AUTHOR_ID,
A.USER_NAME,
A.PASSWORD,
A.EMAIL,
A.BIOGRAPHY,
P.POST_ID,
P.BLOG_ID
AS BLOG_POST_ID ,
P.CREATE_TIME,
P.SUBJECT,
P.BODY,
P.DRAFT
FROM
BLOG B
LEFT
OUTER JOIN AUTHOR A
ON
B.AUTHOR_ID = A.AUTHOR_ID
LEFT
OUTER JOIN POST P
ON
P.BLOG_ID = B.BLOG_ID
</ select >
|
1
2
3
4
5
6
7
8
9
10
11
12
|
/*
*
获取所有Blog的所有信息
*/
public
static
BlogInfo nestedResultOnTest()
{
SqlSession
session = sqlSessionFactory.openSession();
BlogInfo
blogInfo = new
BlogInfo();
blogInfo
= (BlogInfo)session.selectOne( "com.foo.bean.BlogMapper.queryAllBlogInfo" );
JSONObject
object = new
JSONObject(blogInfo);
System.out.println(object.toString());
return
blogInfo;
}
|
嵌套结果查询的执行步骤:
1.根据表的对应关系,进行join操作,获取到结果集;
2. 根据结果集的信息和BlogInfo 的resultMap定义信息,对返回的结果集在内存中进行组装、赋值,构造BlogInfo;
3. 返回构造出来的结果List<BlogInfo> 结果。
对于关联的结果查询,如果是多对一的关系,则通过形如 <association property="author" column="blog_author_id" javaType="com.foo.bean.Author"> 进行配置,Mybatis会通过column属性对应的author_id 值去从内存中取数据,并且封装成Author对象;
如果是一对多的关系,就如Blog和Post之间的关系,通过形如 <collection property="posts" column="blog_post_id" ofType="com.foo.bean.Post">进行配置,MyBatis通过 blog_Id去内存中取Post对象,封装成List<Post>;
对于关联结果的查询,只需要查询数据库一次,然后对结果的整合和组装全部放在了内存中。
以上是通过查询Blog所有信息来演示了一对多和多对一的映射对象处理。
ps:自身关联映射示例:
实体类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
public
class
Module {
private
int
id;
private
String key;
private
String name;
private
Module parentModule;
private
List<Module> childrenModules;
private
String url;
private
int
sort;
private
String show;
private
String del;
public
int
getId() {
return
id;
}
public
void
setId( int
id) {
this .id
= id;
}
public
String getKey() {
return
key;
}
public
void
setKey(String key) {
this .key
= key;
}
public
String getName() {
return
name;
}
public
void
setName(String name) {
this .name
= name;
}
public
Module getParentModule() {
return
parentModule;
}
public
void
setParentModule(Module parentModule) {
this .parentModule
= parentModule;
}
public
String getUrl() {
return
url;
}
public
void
setUrl(String url) {
this .url
= url;
}
public
int
getSort() {
return
sort;
}
public
void
setSort( int
sort) {
this .sort
= sort;
}
public
String getShow() {
return
show;
}
public
void
setShow(String show) {
this .show
= show;
}
public
String getDel() {
return
del;
}
public
void
setDel(String del) {
this .del
= del;
}
public
List<Module> getChildrenModules() {
return
childrenModules;
}
public
void
setChildrenModules(List<Module> childrenModules) {
this .childrenModules
= childrenModules;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
< mapper
namespace = "com.sagaware.caraccess.mapper.ModuleMapper" >
< resultMap
type = "Module"
id = "moduleResultMap" >
< id
property = "id"
column = "module_id" />
< result
property = "key"
column = "module_key" />
< result
property = "name"
column = "module_name" />
< result
property = "url"
column = "module_url" />
< result
property = "sort"
column = "module_sort" />
< result
property = "show"
column = "module_show" />
< result
property = "del"
column = "module_del" />
<!--
查询父模块 -->
< association
property = "parentModule"
column = "module_parent_id"
select = "getModulesById"
/>
<!--
查询子模块 -->
< collection
property = "childrenModules"
column = "module_id"
select = "getChildrenModues"
/>
</ resultMap >
< select
id = "getModules"
parameterType = "String"
resultMap = "moduleResultMap" >
select
* from tb_module where module_id=2
</ select >
< select
id = "getModulesById"
parameterType = "int"
resultMap = "moduleResultMap" >
select
* from tb_module where module_id = #{module_id}
</ select >
< select
id = "getChildrenModues"
parameterType = "int"
resultMap = "moduleResultMap" >
select
* from tb_module where module_parent_id = #{module_id}
</ select >
</ mapper >
|
如对本文有疑问,请提交到交流社区,广大热心网友会为你解答!! 点击进入社区
您可能感兴趣的文章:
相关文章
- 2017-04-04Java集合删除元素ArrayList实例详解
- 2015-05-05浅谈Java三大框架与应用
- 2013-11-11用Java实现希尔排序的示例
- 2017-06-06Java新特性之Nashorn_动力节点Java学院整理
- 2017-03-03Spring Boot如何解决Mysql断连问题
- 2013-12-12java 四舍五入使java保留2位小数示例讲解
- 2017-05-05Java中的对象和引用详解
- 2016-04-04Java多线程编程中线程锁与读写锁的使用示例
- 2017-05-05java application maven项目打自定义zip包实例(推荐)
- 2014-09-09Java中三种简单注解介绍和代码实例
最新评论
-
-
手机登录
相关推荐
- 用R收集和映射推特数据的初学者向导
- JavaScript Source Code映射引起的一个SAP C4C代码调试问题
- 190313-Matlab矩阵映射
- 行为者网络理论(ANT,Actor Network Theory):一切皆是映射
- InterValue正式启动主网映射
- 0day笔记(1)PE文件格式与虚拟文件内存的映射
- 铂链第6课 imToken里的BTO映射到铂链主网钱包操作指南
- Hibernate 映射文件配置
- .NET平台开源项目速览(14)最快的对象映射组件Tiny Mapper
- mybatis进阶(1)--高级映射之数据模型分析
- 文献阅读 - Searching and Mining Trillions of Time Series Subsequences under Dynamic Time Warping
- Java JTS & 空间数据模型