欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

實(shí)例講解Java的MyBatis框架對(duì)MySQL中數(shù)據(jù)的關(guān)聯(lián)查詢

 更新時(shí)間:2016年06月01日 15:50:43   作者:亦山  
這里我們來以實(shí)例講解Java的MyBatis框架對(duì)MySQL中數(shù)據(jù)的關(guān)聯(lián)查詢,包括一對(duì)多、多對(duì)一的關(guān)聯(lián)查詢以及自身關(guān)聯(lián)映射的方法等,需要的朋友可以參考下

mybatis 提供了高級(jí)的關(guān)聯(lián)查詢功能,可以很方便地將數(shù)據(jù)庫獲取的結(jié)果集映射到定義的Java Bean 中。下面通過一個(gè)實(shí)例,來展示一下Mybatis對(duì)于常見的一對(duì)多和多對(duì)一關(guān)系復(fù)雜映射是怎樣處理的。
設(shè)計(jì)一個(gè)簡(jiǎn)單的博客系統(tǒng),一個(gè)用戶可以開多個(gè)博客,在博客中可以發(fā)表文章,允許發(fā)表評(píng)論,可以為文章加標(biāo)簽。博客系統(tǒng)主要有以下幾張表構(gòu)成:
Author表:作者信息表,記錄作者的信息,用戶名和密碼,郵箱等。
Blog表   :  博客表,一個(gè)作者可以開多個(gè)博客,即Author和Blog的關(guān)系是一對(duì)多。
Post表  : 文章記錄表,記錄文章發(fā)表時(shí)間,標(biāo)題,正文等信息;一個(gè)博客下可以有很多篇文章,Blog 和Post的關(guān)系是一對(duì)多。
Comments表:文章評(píng)論表,記錄文章的評(píng)論,一篇文章可以有很多個(gè)評(píng)論:Post和Comments的對(duì)應(yīng)關(guān)系是一對(duì)多。
Tag表:標(biāo)簽表,表示文章的標(biāo)簽分類,一篇文章可以有多個(gè)標(biāo)簽,而一個(gè)標(biāo)簽可以應(yīng)用到不同的文章上,所以Tag和Post的關(guān)系是多對(duì)多的關(guān)系;(Tag和Post的多對(duì)多關(guān)系通過Post_Tag表體現(xiàn))
Post_Tag表: 記錄 文章和標(biāo)簽的對(duì)應(yīng)關(guān)系。

201661153922692.png (889×595)

一般情況下,我們會(huì)根據(jù)每一張表的結(jié)構(gòu) 創(chuàng)建與此相對(duì)應(yīng)的JavaBean(或者Pojo),來完成對(duì)表的基本CRUD操作。

201661154013811.png (819×626)

上述對(duì)單個(gè)表的JavaBean定義有時(shí)候不能滿足業(yè)務(wù)上的需求。在業(yè)務(wù)上,一個(gè)Blog對(duì)象應(yīng)該有其作者的信息和一個(gè)文章列表,如下圖所示:

201661154042218.png (563×241)

如果想得到這樣的類的實(shí)例,則最起碼要有一下幾步:
1. 通過Blog 的id 到Blog表里查詢Blog信息,將查詢到的blogId 和title 賦到Blog對(duì)象內(nèi);
2. 根據(jù)查詢到到blog信息中的authorId 去 Author表獲取對(duì)應(yīng)的author信息,獲取Author對(duì)象,然后賦到Blog對(duì)象內(nèi);
3. 根據(jù) blogId 去 Post表里查詢 對(duì)應(yīng)的 Post文章列表,將List<Post>對(duì)象賦到Blog對(duì)象中;
這樣的話,在底層最起碼調(diào)用三次查詢語句,請(qǐng)看下列的代碼:

/* 
 * 通過blogId獲取BlogInfo對(duì)象 
 */ 
public static BlogInfo ordinaryQueryOnTest(String blogId) 
{ 
 BigDecimal id = new BigDecimal(blogId); 
 SqlSession session = sqlSessionFactory.openSession(); 
 BlogInfo blogInfo = new BlogInfo(); 
 //1.根據(jù)blogid 查詢Blog對(duì)象,將值設(shè)置到blogInfo中 
 Blog blog = (Blog)session.selectOne("com.foo.bean.BlogMapper.selectByPrimaryKey",id); 
 blogInfo.setBlogId(blog.getBlogId()); 
 blogInfo.setTitle(blog.getTitle()); 
  
 //2.根據(jù)Blog中的authorId,進(jìn)入數(shù)據(jù)庫查詢Author信息,將結(jié)果設(shè)置到blogInfo對(duì)象中 
 Author author = (Author)session.selectOne("com.foo.bean.AuthorMapper.selectByPrimaryKey",blog.getAuthorId()); 
 blogInfo.setAuthor(author); 
  
 //3.查詢posts對(duì)象,設(shè)置進(jìn)blogInfo中 
 List posts = session.selectList("com.foo.bean.PostMapper.selectByBlogId",blog.getBlogId()); 
 blogInfo.setPosts(posts); 
 //以JSON字符串的形式將對(duì)象打印出來 
 JSONObject object = new JSONObject(blogInfo); 
 System.out.println(object.toString()); 
 return blogInfo; 
} 

從上面的代碼可以看出,想獲取一個(gè)BlogInfo對(duì)象比較麻煩,總共要調(diào)用三次數(shù)據(jù)庫查詢,得到需要的信息,然后再組裝BlogInfo對(duì)象。

嵌套語句查詢
mybatis提供了一種機(jī)制,叫做嵌套語句查詢,可以大大簡(jiǎn)化上述的操作,加入配置及代碼如下:

<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> 

/* 
 * 通過blogId獲取BlogInfo對(duì)象 
 */ 
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; 
} 

通過上述的代碼完全可以實(shí)現(xiàn)前面的那個(gè)查詢。這里我們?cè)诖a里只需要 blogInfo = (BlogInfo)session.selectOne("com.foo.bean.BlogMapper.queryBlogInfoById",id);一句即可獲取到復(fù)雜的blogInfo對(duì)象。

嵌套語句查詢的原理
在上面的代碼中,Mybatis會(huì)執(zhí)行以下流程:
1.先執(zhí)行 queryBlogInfoById 對(duì)應(yīng)的語句從Blog表里獲取到ResultSet結(jié)果集;
2.取出ResultSet下一條有效記錄,然后根據(jù)resultMap定義的映射規(guī)格,通過這條記錄的數(shù)據(jù)來構(gòu)建對(duì)應(yīng)的一個(gè)BlogInfo 對(duì)象。
3. 當(dāng)要對(duì)BlogInfo中的author屬性進(jìn)行賦值的時(shí)候,發(fā)現(xiàn)有一個(gè)關(guān)聯(lián)的查詢,此時(shí)Mybatis會(huì)先執(zhí)行這個(gè)select查詢語句,得到返回的結(jié)果,將結(jié)果設(shè)置到BlogInfo的author屬性上;
4. 對(duì)BlogInfo的posts進(jìn)行賦值時(shí),也有上述類似的過程。
5. 重復(fù)2步驟,直至ResultSet. next () == false;
以下是blogInfo對(duì)象構(gòu)造賦值過程示意圖:

201661154146597.png (933×418)

這種關(guān)聯(lián)的嵌套查詢,有一個(gè)非常好的作用就是:可以重用select語句,通過簡(jiǎn)單的select語句之間的組合來構(gòu)造復(fù)雜的對(duì)象。上面嵌套的兩個(gè)select語句com.foo.bean.AuthorMapper.selectByPrimaryKey和com.foo.bean.PostMapper.selectByBlogId完全可以獨(dú)立使用。

N+1問題
它的弊端也比較明顯:即所謂的N+1問題。關(guān)聯(lián)的嵌套查詢顯示得到一個(gè)結(jié)果集,然后根據(jù)這個(gè)結(jié)果集的每一條記錄進(jìn)行關(guān)聯(lián)查詢。
現(xiàn)在假設(shè)嵌套查詢就一個(gè)(即resultMap 內(nèi)部就一個(gè)association標(biāo)簽),現(xiàn)查詢的結(jié)果集返回條數(shù)為N,那么關(guān)聯(lián)查詢語句將會(huì)被執(zhí)行N次,加上自身返回結(jié)果集查詢1次,共需要訪問數(shù)據(jù)庫N+1次。如果N比較大的話,這樣的數(shù)據(jù)庫訪問消耗是非常大的!所以使用這種嵌套語句查詢的使用者一定要考慮慎重考慮,確保N值不會(huì)很大。
以上面的例子為例,select 語句本身會(huì)返回com.foo.bean.BlogMapper.queryBlogInfoById 條數(shù)為1 的結(jié)果集,由于它有兩條關(guān)聯(lián)的語句查詢,它需要共訪問數(shù)據(jù)庫 1*(1+1)=3次數(shù)據(jù)庫。

嵌套結(jié)果查詢
嵌套語句的查詢會(huì)導(dǎo)致數(shù)據(jù)庫訪問次數(shù)不定,進(jìn)而有可能影響到性能。Mybatis還支持一種嵌套結(jié)果的查詢:即對(duì)于一對(duì)多,多對(duì)多,多對(duì)一的情況的查詢,Mybatis通過聯(lián)合查詢,將結(jié)果從數(shù)據(jù)庫內(nèi)一次性查出來,然后根據(jù)其一對(duì)多,多對(duì)一,多對(duì)多的關(guān)系和ResultMap中的配置,進(jìn)行結(jié)果的轉(zhuǎn)換,構(gòu)建需要的對(duì)象。
重新定義BlogInfo的結(jié)果映射 resultMap

<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> 

對(duì)應(yīng)的sql語句如下:

<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> 

/* 
 * 獲取所有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; 
} 

嵌套結(jié)果查詢的執(zhí)行步驟:
1.根據(jù)表的對(duì)應(yīng)關(guān)系,進(jìn)行join操作,獲取到結(jié)果集;
2. 根據(jù)結(jié)果集的信息和BlogInfo 的resultMap定義信息,對(duì)返回的結(jié)果集在內(nèi)存中進(jìn)行組裝、賦值,構(gòu)造BlogInfo;
3. 返回構(gòu)造出來的結(jié)果List<BlogInfo> 結(jié)果。
對(duì)于關(guān)聯(lián)的結(jié)果查詢,如果是多對(duì)一的關(guān)系,則通過形如 <association property="author" column="blog_author_id" javaType="com.foo.bean.Author"> 進(jìn)行配置,Mybatis會(huì)通過column屬性對(duì)應(yīng)的author_id 值去從內(nèi)存中取數(shù)據(jù),并且封裝成Author對(duì)象;
如果是一對(duì)多的關(guān)系,就如Blog和Post之間的關(guān)系,通過形如 <collection property="posts" column="blog_post_id" ofType="com.foo.bean.Post">進(jìn)行配置,MyBatis通過 blog_Id去內(nèi)存中取Post對(duì)象,封裝成List<Post>;
對(duì)于關(guān)聯(lián)結(jié)果的查詢,只需要查詢數(shù)據(jù)庫一次,然后對(duì)結(jié)果的整合和組裝全部放在了內(nèi)存中。
以上是通過查詢Blog所有信息來演示了一對(duì)多和多對(duì)一的映射對(duì)象處理。

ps:自身關(guān)聯(lián)映射示例:
實(shí)體類

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; 
 } 
} 

XML代碼:
<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> 

相關(guān)文章

  • SpringBoot2.x入門教程之引入jdbc模塊與JdbcTemplate簡(jiǎn)單使用方法

    SpringBoot2.x入門教程之引入jdbc模塊與JdbcTemplate簡(jiǎn)單使用方法

    這篇文章主要介紹了SpringBoot2.x入門教程之引入jdbc模塊與JdbcTemplate簡(jiǎn)單使用方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • Java新API的時(shí)間格式化

    Java新API的時(shí)間格式化

    這篇文章主要介紹了Java新API的時(shí)間格式化,新的時(shí)間API的時(shí)間格式化由java.time.format.DateTimeFormatter負(fù)責(zé),更多相關(guān)資料需要的小伙伴可以參考一下
    2022-05-05
  • SpringBoot中使用JWT的實(shí)戰(zhàn)

    SpringBoot中使用JWT的實(shí)戰(zhàn)

    本文主要介紹了SpringBoot中使用JWT的實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Java?Timer使用講解

    Java?Timer使用講解

    Timer是一種工具,線程用其安排以后在后臺(tái)線程中執(zhí)行的任務(wù)??砂才湃蝿?wù)執(zhí)行一次,或者定期重復(fù)執(zhí)行,這篇文章主要介紹了Java?Timer使用講解,需要的朋友可以參考下
    2022-11-11
  • SpringBoot常用計(jì)量與bean屬性校驗(yàn)和進(jìn)制數(shù)據(jù)轉(zhuǎn)換規(guī)則全面分析

    SpringBoot常用計(jì)量與bean屬性校驗(yàn)和進(jìn)制數(shù)據(jù)轉(zhuǎn)換規(guī)則全面分析

    這篇文章主要介紹了SpringBoot常用計(jì)量、bean屬性校驗(yàn)與進(jìn)制數(shù)據(jù)轉(zhuǎn)換規(guī)則,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-10-10
  • 舉例講解Java中的多線程編程

    舉例講解Java中的多線程編程

    這篇文章主要介紹了舉例講解Java中的多線程編程,線程是Java學(xué)習(xí)中的重要知識(shí),需要的朋友可以參考下
    2015-09-09
  • Java字符串無意識(shí)的遞歸過程解析

    Java字符串無意識(shí)的遞歸過程解析

    這篇文章主要介紹了Java字符串無意識(shí)的遞歸過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • Kotlin 的注解類詳解及實(shí)例

    Kotlin 的注解類詳解及實(shí)例

    這篇文章主要介紹了Kotlin 的注解類詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • java網(wǎng)上圖書商城(7)訂單模塊2

    java網(wǎng)上圖書商城(7)訂單模塊2

    這篇文章主要為大家詳細(xì)介紹了java網(wǎng)上圖書商城,訂單模塊第二篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • JAVA語法糖原理你知道嗎

    JAVA語法糖原理你知道嗎

    語法糖(Syntactic sugar),也叫做糖衣語法,是英國科學(xué)家發(fā)明的一個(gè)術(shù)語,通常來說使用語法糖能夠增加程序的可讀性,從而減少程序代碼出錯(cuò)的機(jī)會(huì).這篇文章主要介紹了Java 中的語法糖知識(shí),需要的朋友可以參考下
    2021-09-09

最新評(píng)論