国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - 實例講解Java的MyBatis框架對MySQL中數據的關聯查詢

實例講解Java的MyBatis框架對MySQL中數據的關聯查詢

2020-05-08 11:55亦山 JAVA教程

這里我們來以實例講解Java的MyBatis框架對MySQL中數據的關聯查詢,包括一對多、多對一的關聯查詢以及自身關聯映射的方法等,需要的朋友可以參考下

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

實例講解Java的MyBatis框架對MySQL中數據的關聯查詢

一般情況下,我們會根據每一張表的結構 創建與此相對應的JavaBean(或者Pojo),來完成對表的基本CRUD操作。

實例講解Java的MyBatis框架對MySQL中數據的關聯查詢

上述對單個表的JavaBean定義有時候不能滿足業務上的需求。在業務上,一個Blog對象應該有其作者的信息和一個文章列表,如下圖所示:

實例講解Java的MyBatis框架對MySQL中數據的關聯查詢

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

/* 
 * 通過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提供了一種機制,叫做嵌套語句查詢,可以大大簡化上述的操作,加入配置及代碼如下:

<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對象 
 */ 
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對象構造賦值過程示意圖:

實例講解Java的MyBatis框架對MySQL中數據的關聯查詢

這種關聯的嵌套查詢,有一個非常好的作用就是:可以重用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

<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語句如下:

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

嵌套結果查詢的執行步驟:
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:自身關聯映射示例:
實體類

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> 

 

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 免费观看av毛片 | 日韩高清国产一区在线 | 国产黄色一级片视频 | 亚洲社区在线 | 久久一区| 久久久久久亚洲 | 亚洲国产精品久久久久久6q | 国产a区 | 碰碰视频 | 欧美日韩在线一区 | 久久69精品久久久久久久电影好 | 日韩一区二区在线免费 | 26uuu成人免费毛片 | 亚洲一区二区三区高清 | 伊人青青操 | 久久综合av | 欧美日韩在线一区 | 成人在线观看免费爱爱 | 久久精品亚洲成在人线av网址 | 可以看av的网站 | 最新高清无码专区 | 国产美女一区二区 | 99视频在线免费观看 | www.国产精品| 国产成人一区 | 日本中文字幕亚洲 | 成人精品鲁一区一区二区 | 亚洲香蕉在线观看 | 九九精品视频在线观看 | 无码一区二区三区视频 | 天天艹| 日韩精品区 | 日韩在线精品视频 | 亚洲成人av免费看 | 亚洲精品久久久久久久蜜桃 | 欧美电影一区 | 亚洲福利一区二区 | 亚洲天堂一区二区 | 白浆在线 | 黄色片视频免费看 | 久久人爱|