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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Hibernate n+1问题

發布時間:2025/7/14 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Hibernate n+1问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  Hibernate?中常會用到?set?,?bag?等集合表示?1?對多的關系,在獲取實體的時候就能根據關系將關聯的對象或者對象集取出,還可以設定?cacade?進行關聯更新和刪除。這不得不說?hibernate?的?orm?做得很好,很貼近?oo?的使用習慣了。

  但是對數據庫訪問還是必須考慮性能問題的,在設定了?1?對多這種關系之后,?查詢就會出現傳說中的?n+1?問題。

?

  出現的情況

一對多: 在一方,查找得到了 n 個對象,那么又需要將 n 個對象關聯的集合取出,于是本來的一條 sql 查詢變成了 n+1 條;多對一: 在多方,查詢得到了 m 個對象,那么也會將 m 個對象對應的 1 方的對象取出, 也變成了 m+1

?

?

  其實這個問題在Hibernate in Action中已經有很多種解決辦法了。

  下面總結一下。

?

需求這樣的,我有四張表(one,two,three,four)從one一直外鍵關聯到four。結構如下

現在在Session中得到One,并從One里一直取到Four里的內容。如果簡單的用Session.get來實現是這樣的。

One one = (One)session.get(One.class,new Integer(1));Iterator iterone = one.getTwos().iterator();while(iterone.hasNext()){Two two = (Two) iterone.next();Iterator itertwo = two.getThrees().iterator();while(itertwo.hasNext()){Three three = (Three) itertwo.next();three.getFours().size(); }}

?

這樣我在Session關閉后返回的One里是從One到Four的信息都有的。
然而這樣做所導致的結果是生成大量的SQL查詢,這是一個典型的n+1 Selects問題。如果系統結構層次多,符合條件的記錄多,那么Hibernate為你生成的SQL查詢將是難以接受的。
對于這個例子生成的SQL是這樣的

Hibernate: select one0_.c_one_id as c1_0_, one0_.c_one_text as c2_3_0_ from Oneone0_ where one0_.c_one_id=? Hibernate: select twos0_.c_one_id as c2_1_, twos0_.c_two_id as c1_1_,twos0_.c_two_id as c1_0_, twos0_.c_one_id as c2_2_0_, twos0_.c_two_text asc3_2_0_ from Two twos0_ where twos0_.c_one_id=? Hibernate: select threes0_.c_two_id as c2_1_, threes0_.c_three_id as c1_1_,threes0_.c_three_id as c1_0_, threes0_.c_two_id as c2_1_0_,threes0_.c_three_text as c3_1_0_ from Three threes0_ where threes0_.c_two_id=? Hibernate: select fours0_.c_three_id as c2_1_, fours0_.c_four_id as c1_1_,fours0_.c_four_id as c1_0_, fours0_.c_three_id as c2_0_0_, fours0_.c_four_textas c3_0_0_ from Four fours0_ where fours0_.c_three_id=? Hibernate: select fours0_.c_three_id as c2_1_, fours0_.c_four_id as c1_1_,fours0_.c_four_id as c1_0_, fours0_.c_three_id as c2_0_0_, fours0_.c_four_textas c3_0_0_ from Four fours0_ where fours0_.c_three_id=? Hibernate: select threes0_.c_two_id as c2_1_, threes0_.c_three_id as c1_1_,threes0_.c_three_id as c1_0_, threes0_.c_two_id as c2_1_0_,threes0_.c_three_text as c3_1_0_ from Three threes0_ where threes0_.c_two_id=? Hibernate: select fours0_.c_three_id as c2_1_, fours0_.c_four_id as c1_1_,fours0_.c_four_id as c1_0_, fours0_.c_three_id as c2_0_0_, fours0_.c_four_textas c3_0_0_ from Four fours0_ where fours0_.c_three_id=? Hibernate: select fours0_.c_three_id as c2_1_, fours0_.c_four_id as c1_1_,fours0_.c_four_id as c1_0_, fours0_.c_three_id as c2_0_0_, fours0_.c_four_textas c3_0_0_ from Four fours0_ where fours0_.c_three_id=?

?


對于這樣的問題,在沒有Hibernate以前我們一般都用jdbc來做,那樣的話我們其實用一個進行3次join的sql語句就可以實現,但是這樣解決也有問題,就是返回的ResultSet中的數據非常多,而且雜亂,其實是從one到four平行排列的。對于這樣的結果集我們要把它手動影射曾對象結構也是一個很復雜的操作。
幸好Hibernate3可以為我們做這些事情(我再一次被Hibernate的強大所震撼)。
上面的實現可以用Criteria來實現:

session = sessionFactory.openSession();Criteria criteria = session.createCriteria(One.class);criteria.add(Expression.eq("COneId",new Integer(1)));one = (One)criteria.setFetchMode("twos",FetchMode.JOIN).setFetchMode("twos.threes",FetchMode.JOIN).setFetchMode("twos.threes.fours",FetchMode.JOIN).uniqueResult();session.close();

?

這里的重點是這句話

criteria.setFetchMode("twos",FetchMode.JOIN)
.setFetchMode("twos.threes",FetchMode.JOIN)
.setFetchMode("twos.threes.fours",FetchMode.JOIN)
.uniqueResult();

?

  在用Criteria之前先設置FetchMode,應為Criteria是動態生成sql語句的,所以生成的sql就是一層層Join下去的。
setFetchMode(String,Mode)第一個參數是association path,用"."來表示路徑。這一點具體的例子很少,文檔也沒有寫清楚。我也是試了很久才試出來的。
就這個例子來所把因為取道第四層,所以要進行三次setFetchMode
第一次的路徑是twos,一位one中有two的Set。這個具體要更具hbm.xml的配置來定。
第二個路徑就是twos.threes
第三個就是twos.threes.fours
一次類推,一層層增加的。
這樣做法最終生成的SQL是這樣的:

Hibernate: select this_.c_one_id as c1_3_, this_.c_one_text as c2_3_3_,twos2_.c_one_id as c2_5_, twos2_.c_two_id as c1_5_, twos2_.c_two_id as c1_0_,twos2_.c_one_id as c2_2_0_, twos2_.c_two_text as c3_2_0_, threes3_.c_two_id asc2_6_, threes3_.c_three_id as c1_6_, threes3_.c_three_id as c1_1_,threes3_.c_two_id as c2_1_1_, threes3_.c_three_text as c3_1_1_,fours4_.c_three_id as c2_7_, fours4_.c_four_id as c1_7_, fours4_.c_four_id asc1_2_, fours4_.c_three_id as c2_0_2_, fours4_.c_four_text as c3_0_2_ from Onethis_ left outer join Two twos2_ on this_.c_one_id=twos2_.c_one_id left outerjoin Three threes3_ on twos2_.c_two_id=threes3_.c_two_id left outer join Fourfours4_ on threes3_.c_three_id=fours4_.c_three_id where this_.c_one_id=?

?


雖然很長但是只有一條SQL語句。性能要好很多。Hibernate的強大之處是它會把返回的ResultSet自動影射到你的對象模型里面去。這就為我們省了很多事。

看來Hibernate真是一個耐人尋味的Framework啊。

源碼,沒什么東西。

?

?

Hibernate N+1 問題及解決辦法

? 1、?使用?fetch?抓取,?Hibernate?抓取策略分為單端代理和集合代理的抓取策略。

Hibernate?抓取策略?(?單端代理的抓取策略?)?

???保持默認也就是如下?:

<many-to-one name="clazz" cascade="save-update" fetch="select" />

?

????fetch="select"?就是另外發送一條?select?語句抓取當前對象關聯實體或者集合設置?fetch="join"??

<many-to-one name="clazz" cascade="save-update" fetch="join"/>

?

Hibernate?會通過?select?語句使用外連接來加載器關聯實體活集合此時?lazy?會失效

???????Hibernate?抓取策略?(?集合代理的抓取策略?)?

????????????保持默認(?fetch="select"?)也就是如下?:? ? ? ??

<set name="students" inverse="true"><key column="clazz"/><one-to-many class="com.june.hibernate.Student"/> </set>

?

?????????????1)fetch="select"?會另外發出一條語句查詢集合

?????????????2)?設置?fetch="join"?采用外連接集合的?lazy?失效

?????????????3)?這只?fetch="subselect"?另外發出一條?select?語句抓取前面查詢到的所有的實體對象的關聯集合?fetch只對?HQL?查詢產生影響其他的則不會

?

? ? ???2、?使用?map?直接搜索需要的列

  如:產品?product?和產品分類?product_category?兩張表,多對一關系。查詢產品列表時

select new Map(p.id as id, p.name as name, p.category.name as categoryName) from Product p

?

?

? ? ? ?3、?延遲檢索策略

  延遲檢索策略能避免多余加載應用程序不需要訪問的關聯對象,

  hibernate3開始已經默認是lazy=true了;lazy=true時不會立刻查詢關聯對象,只有當需要關聯對象(訪問其屬性)時才會發生查詢動作。

?? ? ? ?4、?迫切左外連接檢索策略

  迫切左外連接檢索策略則充分利用了SQL的外連接查詢功能,能夠減少select語句的數目。

  可以在映射文件中定義連接抓取方式。

<set name=”orders” fetch=”join”><key column=”customer_id”><one-to-many class="com.hibernate.mappings.Order"/></set>

?

或者使用HQL的LEFT OUTER JOIN.

或者在條件查詢中使用setFetchMode(FetchMode.JOIN)

Customer ctm = (Customer)session.createCriteria(Customer.class).setFetchMode(“Order”.JOIN).add(Restrictions.idEq(customer_id));

?

轉載于:https://www.cnblogs.com/hwaggLee/p/4440263.html

總結

以上是生活随笔為你收集整理的Hibernate n+1问题的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 欧美一区二区三区在线免费观看 | 欧美性插动态图 | 欧美一区精品 | 超碰日韩 | 阿v视频免费在线观看 | 久久精品视频在线 | 欧美激情视频一区二区三区不卡 | 欧美一级无毛 | 91在线网站| 久久理论电影 | 国产情侣酒店自拍 | 乱色熟女综合一区二区三区 | 成人a级网站 | 一个人看的毛片 | 吸咬奶头狂揉60分钟视频 | 久久亚洲国产成人精品性色 | 成人一级网站 | h片在线观看网站 | 哪里可以看免费毛片 | 中文字幕日韩在线视频 | 蜜臀999 | 日韩精品电影网 | 久久久免费观看 | 韩国毛片一区二区三区 | 欧美无砖区 | 日本三不卡 | 黄色片久久久久 | 日日夜夜狠狠 | 国产精品午夜福利 | 国产精品免费在线播放 | 免费网站在线观看视频 | 亚洲天堂伊人 | 国产欧美自拍 | 草逼视频网站 | 久久精品国产亚洲av麻豆蜜芽 | 色老头一区二区三区 | 成人在线欧美 | 国产无码精品久久久 | 中文字幕免费中文 | 久久一区二区三区四区五区 | 国产传媒中文字幕 | 精品国产黄 | 高清一区二区视频 | 香蕉视频A| 免费在线观看不卡av | 免费成人深夜 | 男生插女生的视频 | 国产女主播一区 | 国模av| 伦伦影院午夜理伦片 | 99中文字幕在线观看 | 日韩精品人妻中文字幕有码 | 黄色网络在线观看 | 西方av在线 | 久久婷婷六月 | 爱情岛成人 | 热99在线观看 | 超碰97在线资源 | 中文字幕亚洲成人 | 9i免费看片黄 | 樱花影院最新免费观看攻略 | 两个人做羞羞的视频 | 玖玖在线 | 国产第一页在线 | 国产又大又粗又爽 | 看毛片网 | 日韩视频一区二区三区在线播放免费观看 | 亚洲四区| 国产一区二区成人 | 欧美深性狂猛ⅹxxx深喉 | 国产精品扒开腿做爽爽 | 日韩精品一区在线播放 | 国产小视频免费观看 | 国产乡下妇女做爰毛片 | 一级做a免费 | 丁香婷婷一区二区三区 | 激情六月综合 | 美日韩黄色片 | 亚洲综合日韩精品欧美综合区 | 国产九色在线播放九色 | 视频在线观看电影完整版高清免费 | 麻豆视| 成人无码www在线看免费 | 欧美大片在线 | 中日韩中文字幕 | 日韩欧美亚洲 | 伊人成综合 | 日韩黄色成人 | 中国一级特黄毛片大片 | 亚洲成人午夜影院 | 青青青网 | 依依综合网 | a国产精品 | 欧美综合在线视频 | 亚洲色图另类小说 | 天堂在线观看中文字幕 | 亚洲亚洲人成综合网络 | 国产伦精品一区二区三区精品 | 香蕉久久久久 |