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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

初始化懒惰关系以及何时使用它们的5种方法

發(fā)布時(shí)間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 初始化懒惰关系以及何时使用它们的5种方法 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

實(shí)體之間關(guān)系的延遲加載是JPA中公認(rèn)的最佳實(shí)踐。 它的主要目標(biāo)是僅從數(shù)據(jù)庫(kù)中檢索請(qǐng)求的實(shí)體,并僅在需要時(shí)加載相關(guān)實(shí)體。 如果我們只需要請(qǐng)求的實(shí)體,那是一個(gè)很好的方法。 但是,如果我們還需要一些相關(guān)實(shí)體,它會(huì)增加工作量,并可能導(dǎo)致性能問(wèn)題。

讓我們看一下觸發(fā)初始化的不同方法及其特定的優(yōu)點(diǎn)和缺點(diǎn)。

1.在映射關(guān)系上調(diào)用方法

讓我們從最顯而易見的方法開始,不幸的是也從效率最低的方法開始。 我們?cè)贓ntityManager上使用find方法,并在關(guān)系上調(diào)用一個(gè)方法。

Order order = this.em.find(Order.class, orderId); order.getItems().size();

此代碼工作得很好,易于閱讀并且經(jīng)常使用。 那么,這是什么問(wèn)題呢?

好吧,您可能知道。 此代碼執(zhí)行附加查詢以初始化關(guān)系。 這聽起來(lái)不像是一個(gè)真正的問(wèn)題,但是可以讓我們計(jì)算出一個(gè)更加真實(shí)的場(chǎng)景中執(zhí)行的查詢的數(shù)量。

假設(shè)我們有一個(gè)具有5個(gè)關(guān)系的實(shí)體,需要初始化。 因此,我們將獲得1 + 5 = 6個(gè)查詢 。 好的,那是5個(gè)附加查詢。 這似乎仍然不是一個(gè)大問(wèn)題。

但是我們的應(yīng)用程序?qū)⒈欢鄠€(gè)用戶并行使用(我希望)。 假設(shè)我們的系統(tǒng)必須為100個(gè)并行用戶提供服務(wù)器。 然后,我們將獲得100 + 5 * 100 = 600個(gè)查詢 。

好的,很明顯,這種方法提供了可行的解決方案,但不是一個(gè)好的解決方案。 或早或晚,額外執(zhí)行的查詢數(shù)量將使我們的應(yīng)用程序變慢。 因此,我們應(yīng)該嘗試避免這種方法,并看看其他一些選擇。

2.在JPQL中獲取Join

初始化惰性關(guān)系的一個(gè)更好的選擇是將JPQL查詢與獲取聯(lián)接一起使用。

Query q = this.em.createQuery("SELECT o FROM Order o JOIN FETCH o.items i WHERE o.id = :id"); q.setParameter("id", orderId); newOrder = (Order) q.getSingleResult();

這告訴實(shí)體管理器在同一查詢中獲取選定的實(shí)體和關(guān)系。 這種方法的優(yōu)缺點(diǎn)很明顯:

優(yōu)點(diǎn)是所有內(nèi)容都在一個(gè)查詢中獲取。 從性能的角度來(lái)看,這比第一種方法要好得多。

主要缺點(diǎn)是我們需要編寫其他代碼來(lái)執(zhí)行查詢。 但是,如果實(shí)體具有多個(gè)關(guān)系,并且我們需要針對(duì)不同的用例初始化不同的關(guān)系,那就更糟了。 在這種情況下,我們需要為獲取聯(lián)接關(guān)系的每個(gè)所需組合編寫查詢。 這會(huì)變得很混亂。

在JPQL語(yǔ)句中使用提取聯(lián)接可能需要大量查詢,這將使維護(hù)代碼庫(kù)變得困難。 因此,在開始編寫大量查詢之前,我們應(yīng)該考慮可能需要的不同訪存聯(lián)接組合的數(shù)量。 如果數(shù)量很少,那么這是一種限制執(zhí)行的查詢數(shù)量的好方法。

3.獲取條件API中的加入

好的,這種方法與以前的方法基本相同。 但是這次我們使用的是Criteria API,而不是JPQL查詢。

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery q = cb.createQuery(Order.class); Root o = q.from(Order.class); o.fetch("items", JoinType.INNER); q.select(o); q.where(cb.equal(o.get("id"), orderId));Order order = (Order)this.em.createQuery(q).getSingleResult();

優(yōu)點(diǎn)和缺點(diǎn)與帶有訪存連接的JPQL查詢相同。 使用一個(gè)查詢從數(shù)據(jù)庫(kù)中檢索實(shí)體和關(guān)系,我們需要每種關(guān)系組合的特定代碼。 但是,如果我們使用的是Criteria API,我們通常已經(jīng)有很多用例特定的查詢代碼。 因此,這可能不是一個(gè)大問(wèn)題。

如果我們已經(jīng)在使用Criteria API來(lái)構(gòu)建查詢,那么這是減少執(zhí)行查詢數(shù)量的好方法。

4.命名實(shí)體圖

命名實(shí)體圖是JPA 2.1的新功能。 它可用于定義應(yīng)從數(shù)據(jù)庫(kù)中查詢的實(shí)體圖。 實(shí)體圖的定義是通過(guò)注釋完成的,并且與查詢無(wú)關(guān)。

如果您不熟悉此功能,則可以查看我以前的一篇博客文章 ,其中對(duì)它進(jìn)行了更詳細(xì)的介紹。

@Entity @NamedEntityGraph(name = "graph.Order.items", attributeNodes = @NamedAttributeNode("items")) public class Order implements Serializable { ....

然后,EntityManager的find方法可以使用命名的實(shí)體圖。

EntityGraph graph = this.em.getEntityGraph("graph.Order.items");Map hints = new HashMap(); hints.put("javax.persistence.fetchgraph", graph);Order order = this.em.find(Order.class, orderId, hints);

這基本上是我們第一種方法的改進(jìn)版本。 實(shí)體管理器將通過(guò)一個(gè)查詢從數(shù)據(jù)庫(kù)檢索定義的實(shí)體圖。 唯一的缺點(diǎn)是,我們需要為將在一個(gè)查詢中檢索到的每種關(guān)系組合注釋一個(gè)命名實(shí)體圖。 與第二種方法一樣,我們將需要更少的附加注釋,但是它仍然會(huì)變得非常混亂。

因此,如果我們只需要定義有限數(shù)量的實(shí)體圖并將其重用于不同的用例,則命名實(shí)體圖是一個(gè)很好的解決方案。 否則,代碼將變得難以維護(hù)。

5.動(dòng)態(tài)實(shí)體圖

動(dòng)態(tài)實(shí)體圖類似于命名實(shí)體圖,并且在以前的一篇文章中也進(jìn)行了解釋。 唯一的區(qū)別是,實(shí)體圖是通過(guò)Java API定義的。

EntityGraph graph = this.em.createEntityGraph(Order.class); Subgraph itemGraph = graph.addSubgraph("items");Map hints = new HashMap(); hints.put("javax.persistence.loadgraph", graph);Order order = this.em.find(Order.class, orderId, hints);

通過(guò)API進(jìn)行定義既可以是優(yōu)點(diǎn),也可以是缺點(diǎn)。 如果我們需要大量用例特定的實(shí)體圖,則最好在特定的Java代碼中定義實(shí)體圖,并且不向該實(shí)體添加附加注釋。 這樣可以避免帶有數(shù)十個(gè)注釋的實(shí)體。 另一方面,動(dòng)態(tài)實(shí)體圖需要??更多代碼和其他方法才能重用。

因此,我建議使用動(dòng)態(tài)實(shí)體圖,如果我們需要定義用例特定的圖,則將不會(huì)重復(fù)使用該圖。 如果我們想重用實(shí)體圖,則更容易注釋命名的實(shí)體圖。

結(jié)論

我們研究了5種不同的初始化惰性關(guān)系的方法。 正如我們所看到的,它們每個(gè)都有其優(yōu)點(diǎn)和缺點(diǎn)。 那么從這篇文章中要記住什么呢?

  • 通過(guò)在映射關(guān)系上調(diào)用方法來(lái)初始化惰性關(guān)系會(huì)導(dǎo)致附加查詢。 出于性能原因,應(yīng)避免這種情況。
  • JPQL語(yǔ)句中的訪存聯(lián)接將查詢數(shù)量減少到一個(gè),但是我們可能需要很多不同的查詢。
  • Criteria API還支持提取連接,對(duì)于每種需要初始化的關(guān)系,我們都需要特定的代碼。
  • 如果我們將在代碼中重用已定義的圖,則命名實(shí)體圖是一個(gè)很好的解決方案。
  • 如果我們需要定義特定于用例的圖,則動(dòng)態(tài)實(shí)體圖可能是更好的解決方案。

翻譯自: https://www.javacodegeeks.com/2014/12/5-ways-to-initialize-lazy-relations-and-when-to-use-them.html

總結(jié)

以上是生活随笔為你收集整理的初始化懒惰关系以及何时使用它们的5种方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。