日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MyBatis嵌套查询解析

發布時間:2025/3/15 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MyBatis嵌套查询解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Mybatis表現關聯關系比hibernate簡單,沒有分那么細致one-to-many、many-to-one、one-to-one。而是只有兩種association(一)、collection(多),表現很簡潔。下面通過一個實例,來展示一下Mybatis對于常見的一對多和多對一關系復雜映射是怎樣處理的。

以最簡單的用戶表訂單表這個最簡單的一對多做示例:

對應的JavaBean:

User:

public class User {private int id;private String name;private Double age;private List<User_orders> orders;// get set 省}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

User_orders:

public class User_orders {private int id;private String name;// get set 省 }
  • 1
  • 2
  • 3
  • 4
  • 5

對應的數據庫:

mysql> desc user; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | NO | | NULL | | | age | double | YES | | NULL | | +-------+-------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec)mysql> desc user_orders; +---------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | NO | | NULL | | | user_id | int(5) | YES | MUL | NULL | | +---------+-------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

現在查詢一個user的id查詢出所有信息.如果不考慮關聯查詢,我們會先根據user的id在user表中查詢出name,age然后設置給User類的時候,再根據該user的id在user_orders表中查詢出所有訂單并設置給User類。這樣的話,在底層最起碼調用兩次查詢語句,得到需要的信息,然后再組裝User對象。

嵌套語句查詢

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

<resultMap type="domain.User" id="user"><id column="id" property="id"/><result column="age" property="age"/><collection column="id" property="orders" ofType="domain.User_orders"select="selectOrderByUser"> <id column="id" property="id"/><result column="name" property="name"/></collection> </resultMap> <select id="selectOrderByUser" parameterType="integer" resultType="domain.User_orders">select id,name from user_orders where user_id = #{id} </select><select id="findById" resultMap="user" parameterType="integer">select * from user where id = #{id}</select>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

測試(可以成功查詢到所有信息):

String config = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(config); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sqlSessionFactory.openSession(); // 執行在bean配置文件中定義的sql語句 User user = session.selectOne("UserMapper.findById", 1); //一句即可獲取到復雜的User對象。 System.out.println(user); session.commit(); session.close();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

嵌套語句查詢的原理

在上面的代碼中,Mybatis會執行以下流程:

  • 1.先執行 findById 對應的語句從User表里獲取到ResultSet結果集;

  • 2.取出ResultSet下一條有效記錄,然后根據resultMap定義的映射規格,通過這條記錄的數據來構建對應的一個User 對象。

  • 當要對User中的orders屬性進行賦值的時候,發現有一個關聯的查詢,此時Mybatis會先執行這個select查詢語句,得到返回的結果,將結果設置到user的orders屬性上

這種關聯的嵌套查詢,有一個非常好的作用就是:可以重用select語句,通過簡單的select語句之間的組合來構造復雜的對象。想如上的兩個select完全可以獨立使用。

嵌套查詢的多對一?
上面的關聯查詢查詢其實是對于一對多的查詢,即從user中查出user_order的信息。?
現在從user_order中查user的信息.?
在User_order表中增加字段user:

public class User_orders {private int id;private String name;private User user;//xxx }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

配置select:

<resultMap type="domain.User_orders" id="user_order"><id column="id" property="id"/><result column="name" property="name"/><association property="user" column="user_id" javaType="domain.User" select="selectUserByOrderId"><id column="id" property="id"/><result column="age" property="age"/></association> </resultMap><select id="selectUserByOrderId" parameterType="INTEGER" resultType="domain.User">select id,age from user where id = #{id}</select><select id="findOne" resultMap="user_order" parameterType="integer">select * from user_orders where id=#{id}</select>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

測試:

SqlSession session = sqlSessionFactory.openSession();// 執行在bean配置文件中定義的sql語句User_orders user_orders= session.selectOne("User_ordersMapper.findOne", 1);System.out.println(user_orders);//查詢到了user_order對應的user的信息session.commit();session.close();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

嵌套查詢的N+1問題

盡管嵌套查詢大量的簡化了存在關聯關系的查詢,但它的弊端也比較明顯:即所謂的N+1問題。關聯的嵌套查詢顯示得到一個結果集,然后根據這個結果集的每一條記錄進行關聯查詢。

現在假設嵌套查詢就一個(即resultMap 內部就一個association標簽),現查詢的結果集返回條數為N,那么關聯查詢語句將會被執行N次,加上自身返回結果集查詢1次,共需要訪問數據庫N+1次。如果N比較大的話,這樣的數據庫訪問消耗是非常大的!所以使用這種嵌套語句查詢的使用者一定要考慮慎重考慮,確保N值不會很大。

以上面一對多(根據user的id查詢order)的例子為例,select 語句本身會返回user條數為1 的結果集,由于它存在有1條關聯的語句查詢,它需要共訪問數據庫 1*(1+1)=2次數據庫。

嵌套結果查詢

嵌套語句的查詢會導致數據庫訪問次數不定,進而有可能影響到性能。Mybatis還支持一種嵌套結果的查詢:即對于一對多,多對多,多對一的情況的查詢,Mybatis通過聯合查詢,將結果從數據庫內一次性查出來,然后根據其一對多,多對一,多對多的關系和ResultMap中的配置,進行結果的轉換,構建需要的對象。

重新定義User的結果映射 resultMap

<resultMap type="domain.User" id="user_auto"> <id column="id" property="id"/><result column="age" property="age"/><collection column="id" property="orders" ofType="domain.User_orders"> <id column="order_id" property="id"/><result column="name" property="name"/></collection> </resultMap>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

對應的sql語句如下:

<select id="findAuth" resultMap="user_auto">select u.id,u.age,o.id as order_id ,o.name,o.user_id as user_id from user u left outer join user_orders oon o.user_id = u.id</select>
  • 1
  • 2
  • 3
  • 4

嵌套結果查詢的執行步驟:

  • 1.根據表的對應關系,進行join操作,獲取到結果集;

  • 根據結果集的信息和user 的resultMap定義信息,對返回的結果集在內存中進行組裝、賦值,構造User;
  • 返回構造出來的結果List 結果。

對于關聯的結果查詢,如果是多對一的關系,則通過形如?<association property="user" column="user_id" javaType="domain.User" >進行配置,Mybatis會通過column屬性對應的user_id 值去從內存中取數據,并且封裝成User_order對象;

如果是一對多的關系,就如User和User_order之間的關系,通過形如?<collection column="id" property="orders" ofType="domain.User_orders">進行配置,MyBatis通過 id去內存中取User_orders對象,封裝成List;

對于關聯結果的查詢,只需要查詢數據庫一次,然后對結果的整合和組裝全部放在了內存中。

以上是通過查詢User表所有信息來演示了一對多和多對一的映射對象處理。

總結

以上是生活随笔為你收集整理的MyBatis嵌套查询解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。