成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JPA2.1 中三個提升應用性能的新功能

ormsf / 1224人閱讀

摘要:只用語句,也能完成很多事情,如果不夠,你還可以調用數據庫的特定功能和存儲過程。在中,并沒有針對存儲過程的實際支持,本地查詢是調用存儲過程的唯一方式。規(guī)范引入了幾個新的功能以應對這些低效操作,比如實體圖,條件更新和存儲過程查詢。

經常在網上看到開發(fā)者們抱怨 JPA 性能低下的帖子或文章,但如果仔細查看這些性能問題,常會發(fā)現導致問題的根本原因大致包括以下幾個:

使用過多的 SQL 查詢從數據庫中獲取所需的實體信息,即我們常說的n+1查詢問題

逐個更新實體,而不是使用單條語句進行更新

使用 Java 應用程序而非數據庫進行大量數據處理

JPA提供了處理這類問題的方法,并給 JPA2.1 增加了一些額外功能,可以極大地提升性能表現,筆者將在本文中解釋如何利用 JPA2.1 的功能避免上述問題。

順便提一下,如果想了解Java項目中更多的典型性能問題,可以參考筆者最近發(fā)布的基于性能調查結果的深度報告,如果你在尋找 JPA 資源,點擊此鏈接便可獲取JPA2.1特征的備忘清單。接下來我們來看看如何用JPA來解決現有的性能問題。

解決「SQL 查詢過多」的問題

根據以往的經驗,使用過多的 SQL 查詢獲取所要求的實體是導致性能問題最普遍的原因。

即使是看起來最簡單的查詢,如果操作不當,也會觸發(fā)幾十次甚至上百次的 SQL 查詢。而且,你在本節(jié)中可以看到,這類不當操作不一定會出現在查詢語句中,而可能只是幾個配置不當的注解。所以,如果你覺得這個問題不會造成影響,請三思。

如果在你的項目中出現以下幾段代碼,你會怎么想?

List authors = this.em.createQuery("SELECT a FROM Author a",
        Author.class).getResultList();

for (Author a : authors) {
    System.out.println("作者 "
            + a.getFirstName()
            + " "
            + a.getLastName()
            + " 書籍信息 "
            + a.getBooks()
                    .stream()
                    .map(b -> b.getTitle() + "("
                            + b.getReviews().size() + " 評論)")
                    .collect(Collectors.joining(", ")));
}

上面的代碼段會打印所有作者的姓名及其書名,看起來非常簡單,但你是否想過它給數據庫發(fā)送了多少次查詢?一次?還是兩次?或者 Author、Book、Review 實體各一次?

實際上,這取決于數據庫中作者的人數。如果數據庫較小,里面只有11名作者和6本書。那么這段代碼會觸發(fā)12次查詢,其中1次用于獲取所有作者姓名,另外11次給每位作者匹配書名。這一問題被稱作 n+1 查詢問題,無論我們使用的是 MySQL、SqlServer 還是其他數據庫,都容易出現此類問題。因此在生產環(huán)境中,隨著數據量不斷增大,代碼的性能就越差。

我們可以通過多種方法,用一次查詢獲取所有要求的實體信息 ,從而避免這一情況。在筆者看來,使用 @NamedEntityGraph 來解決此問題是最新,也最好的方法。

實體圖通過獨立于查詢的方法指定應該從數據庫中獲取的實體的圖。這意味著,你需要為實體圖創(chuàng)建一個獨立的定義,并在需要時與查詢合并。下段代碼展示了如何定義根據作者名提取書名的 @NamedEntityGraph。

@Entity
@NamedEntityGraph(name = "graph.AuthorBooks", attributeNodes = @NamedAttributeNode("books"))
public class Author implements Serializable {
…
}

現在,實體管理器可以用這個圖為參考,通過一次查詢獲取所有作者和書名。在圖的定義中可以看到,筆者只提供了包含相關實體的屬性名稱。因此,筆者將@NamedEntityGraph作為loadgraph (負載圖),這樣便可提取其他所有屬性及其定義的獲取類型,如下所示:

EntityGraph graph = this.em.getEntityGraph("graph.AuthorBooks");

List authors = this.em
.createQuery("SELECT DISTINCT a FROM Author a", Author.class)
.setHint("javax.persistence.loadgraph", graph).getResultList();

該示例展示了一個非常簡單的實體圖,在實際的應用中,很可能會用到更復雜的圖,但這也不成問題。你可以定義多個 @NamedAttributeNodes 以定義更復雜的圖,也可以用 @NamedSubGraph 注解來創(chuàng)建多層次的圖。如果想了解更多關于 @NamedEntityGraphs 的信息,請點擊實體圖使用方式詳解。

在某些使用案例中,你可能還需要用更動態(tài)的方式來定義實體圖,比如,根據一些輸入參數進行定義。在此類案例中,通過 Java API 用編程的方式定義實體圖效果更佳。

解決「逐個更新實體」的問題

逐個更新實體是造成 JPA 性能問題的另一個常見原因。作為 Java 開發(fā)者,我們習慣處理對象,并用面向對象的方式思考問題。盡管這是實現復雜邏輯和應用的好方法,但也是處理數據庫時導致性能退化的一個常見原因。

從面向對象的角度來看,對實體進行更新和刪除操作是完全可以接受的。但當你不得不更新一大組實體時,這種操作就會非常低效。持久性提供者(Persistence Provider)將為每個更新實體創(chuàng)建一個更新語句,并在下一次 flush 操作時發(fā)送至數據庫中。

然而,SQL 提供了一個更為高效的方式。它允許你創(chuàng)建可一次性更新多個實體的更新語句。你還可以對 JPA 2.1 引入的 CriteriaUpdateCriteriaDelete 語句進行同樣的操作。

如果你之前用過 criteria 條件查詢,肯定對新的 CriteriaUpdate 以及 CriteriaDelete 語句非常熟悉,更新和刪除操作的創(chuàng)建方式幾乎與 JPA 2.0 中引入的 criteria 條件查詢創(chuàng)建方式一樣。

在下面的代碼段中可以看到,你需要從實體管理器中獲取 CriteriaBuilder 并用它創(chuàng)建 CriteriaUpdate 對象,對 CriteriaQuery 進行的操作與此類似,主要區(qū)別在于用于定義更新操作的 set 方法。

CriteriaBuilder cb = this.em.getCriteriaBuilder();
// create update
CriteriaUpdate update = cb.createCriteriaUpdate(Author.class);
// set the root class
Root a = update.from(Author.class);
// set update and where clause
update.set(Author_.firstName, cb.concat(a.get(Author_.firstName), " - updated"));
update.where(cb.greaterThanOrEqualTo(a.get(Author_.id), 3L));

// perform update
Query q = this.em.createQuery(update);
q.executeUpdate();

CriteriaDelete 操作中,你只需要在實體管理器中調用 createCriteriaDelete 方法以獲取 CriteriaDelete 對象,并用它來定義與上例類似的 FROMWHERE 查詢部分。

在數據庫中處理數據

作為 Java 開發(fā)者,我們傾向于在 Java 中實現所有的應用邏輯,這也是造成性能問題的一大常見原因。別誤會,在 Java 中實現邏輯的好處很多,但如果將部分邏輯實現在數據庫中,只把結果發(fā)送到業(yè)務邏輯層,也能得到很好的效果。

在數據庫中執(zhí)行邏輯的方法很多。只用 SQL 語句,也能完成很多事情,如果不夠,你還可以調用數據庫的特定功能和存儲過程。在本文中,筆者將仔細探討存儲過程,更確切地說是探討調用存儲過程的方式。

在 JPA 2.0 中,并沒有針對存儲過程的實際支持,本地查詢是調用存儲過程的唯一方式。JPA 2.1.引入了 @NamedStoredProcedureQuery 和更為動態(tài)的 StoredProcedureQuery,改變了這一現狀。在本文中,筆者將重點關注基于注解的、用 @NamedStoredProcedureQuery 進行調用的存儲過程的定義。筆者在自己的博客中詳細介紹了動態(tài)存儲過程查詢 。

在下面代碼段中可以看到, @NamedStoredProcedureQuery 的定義非常簡潔,你需要指定查詢的名稱、數據庫中的存儲過程名稱以及輸入和輸出參數。在本例中,筆者用輸入參數 xy 調用存儲過程 calculate,期望的輸出參數為 sum,其它支持的參數類型還有用于輸入和輸出的參數 INPUT 和用于檢索結果集的 REF_COURSOR。

@NamedStoredProcedureQuery(
name = "calculate",
procedureName = "calculate",
parameters = {
@StoredProcedureParameter(mode = ParameterMode.IN, type = Double.class, name = "x"),
@StoredProcedureParameter(mode = ParameterMode.IN, type = Double.class, name = "y"),
@StoredProcedureParameter(mode = ParameterMode.OUT, type = Double.class, name = "sum") })

@NamedStoredProcedureQuery 的使用方法與 @NamedQuery 相似,你需要向實體管理器的createNamedStoredProcedureQuery 方法提供查詢名稱,以便在本次查詢中獲取 StoredProcedureQuery 對象,然后,用 setParameter 方法設定輸入參數,之后再用 execute 方法調用存儲過程。

StoredProcedureQuery query = this.em.createNamedStoredProcedureQuery("calculate");
query.setParameter("x", 1.23d);
query.setParameter("y", 4.56d);
query.execute();
Double sum = (Double) query.getOutputParameterValue("sum");
總結

JPA 給數據庫存儲和檢索帶來諸多便利。通過這一工具,可快速開展項目,解決大部分問題,但也更容易導致實現非常低效的持久層。由此,普遍存在的問題包括:使用過多查詢獲取所需數據、逐個更新實體以及在 Java 中執(zhí)行所有邏輯。

JPA 2.1規(guī)范引入了幾個新的功能以應對這些低效操作,比如實體圖(entity graphs),條件更新(criteria update)和存儲過程查詢(stored procedure queries)。筆者的JPA2.1新功能備忘單囊括了JPA 2.1的這些功能及其他新功能,你可以免費下載。

(編譯自:http://zeroturnaround.com/rebellabs/three-jpa-2-1-features-that-will-boost-your-applications-performance/)

OneAPM 為您提供端到端的 Java 應用性能解決方案,我們支持所有常見的 Java 框架及應用服務器,助您快速發(fā)現系統(tǒng)瓶頸,定位異常根本原因。分鐘級部署,即刻體驗,Java 監(jiān)控從來沒有如此簡單。想閱讀更多技術文章,請訪問 OneAPM 官方技術博客。

本文轉自 OneAPM 官方博客

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://systransis.cn/yun/65344.html

相關文章

  • JPA2.1 三個提升應用性能功能

    摘要:只用語句,也能完成很多事情,如果不夠,你還可以調用數據庫的特定功能和存儲過程。在中,并沒有針對存儲過程的實際支持,本地查詢是調用存儲過程的唯一方式。規(guī)范引入了幾個新的功能以應對這些低效操作,比如實體圖,條件更新和存儲過程查詢。 經常在網上看到開發(fā)者們抱怨 JPA 性能低下的帖子或文章,但如果仔細查看這些性能問題,常會發(fā)現導致問題的根本原因大致包括以下幾個: 使用過多的 SQL 查詢從...

    qpwoeiru96 評論0 收藏0

發(fā)表評論

0條評論

ormsf

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<