1. 程式人生 > >高性能 Java 持久化的 14 個技巧

高性能 Java 持久化的 14 個技巧

數據庫查詢 manytoone 匹配 int event overflow 主從復制 stat 響應時間

一個高性能的數據訪問層需要大量關於數據庫內部、JDBC、JPA、Hibernate的知識,本文總結了一些可用來優化企業應用程序的重要的技術。

1. SQL語句日誌

如果您用了生成符合自己使用習慣的語句的框架,則應始終驗證每個語句的有效性和效率。測試時使用斷言機制驗證更好,因為即使在提交代碼之前,也可以捕獲N + 1個查詢問題。

2.連接管理

數據庫的連接開銷非常大,因此您應該始終使用連接池機制。

由於連接數由底層數據庫集群的功能給出,所以您需要盡可能快地釋放連接。

在性能調優中,你總是要測量、設置出正確的連接池,池的大小又是差不多的。 但像FlexyPool這樣工具可以幫助您找到合適的大小,即使您已經將應用程序部署到生產環境中。

3.JDBC批處理

JDBC批處理允許我們在單個數據庫往返中發送多個SQL語句。性能增益在驅動程序和數據庫端都很重要。PreparedStatements 非常適合批處理,而某些數據庫系統(例如 Oracle)僅支持用於預處理語句的批處理。

由於JDBC為批處理定義了獨特的API(例如PreparedStatement.addBatch和PreparedStatement.executeBatch),如果您手動生成語句,那麽您應該從一開始就知道是否應該使用批處理。 使用Hibernate,您可以切換到使用單個配置的批處理。

Hibernate 5.2 提供了會話級別的批處理,所以在這方面更加靈活。

4.語句緩存

語句緩存是您可以輕松利用的最鮮為人知的性能優化之一。 根據基礎的JDBC驅動程序,可以在客戶端(驅動程序)或數據庫端(語法樹甚至執行計劃)上緩存PreparedStatements。

5.Hibernate 標識符

當使用Hibernate時,IDENTITY生成器不是一個好的選擇,因為它禁用了JDBC批處理。

TABLE生成器更糟糕,因為它使用一個單獨的事務來獲取新的標識符,這會對底層事務日誌以及連接池造成壓力,因為每次我們需要一個新的標識符時都需要單獨的連接。

SEQUENCE是正確的選擇,甚至從2012版本就開始支持SQL Server。對於SEQUENCE標識符,Hibernate一直提供優化器,如pooled 或 pooled-lo,這可以減少獲取新的實體標識符值所需的數據庫往返次數。

6.選擇正確的列類型

您應該始終在數據庫端使用正確的列類型。 列類型越緊湊,數據庫工作集中可容納的條目越多,索引將更好地適應於內存。 為此,您應該利用特定於數據庫的類型(例如PostgreSQL中的IPv4地址的inet),尤其是在實現新自定義類型時,Hibernate非常靈活。

7 .關系

Hibernate 帶有許多關系映射類型,但並不是所有的關系映射類型在效率上都是相等的。

技術分享

應該避免單向集合和@ManyToMany列表。如果您確實需要使用實體集合,則首選雙向 @OneToMany關聯。對於@ManyToMany關系,使用 Set(s),因為在這種情況下它們更高效,或者簡單地映射鏈接的多對多表,並將@ManyToMany關系轉換為兩個雙向的 @OneToMany 關聯。

然而,與查詢不同,集合不夠靈活,因為它們不易分頁,這意味著當子關聯的數量相當高時,我們不能使用它們。出於這個原因,你應該考慮一個集合是否真的有必要。 在許多情況下,實體查詢可能是更好的選擇。

8.繼承

就繼承而言,面向對象語言和關系數據庫之間的不匹配變得更加明顯。 JPA提供了SINGLE_TABLE,JOINED和TABLE_PER_CLASS來處理繼承映射,每個策略都有其優缺點。

SINGLE_TABLE在SQL語句方面表現最好,但由於我們不能使用NOT NULL約束,所以我們在數據完整性方面失敗了。

當同時提供更復雜的語句時,JOINED采用數據完整性限制。 只要你不使用基本類型的多態查詢或@OneToMany關聯,這個策略就沒有問題。 它的真正的作用在於對數據訪問層上由策略模式支持的多態@ManyToOne關聯。

應該避免使用TABLE_PER_CLASS,因為它不會生成有效的SQL語句。

9.持久性上下文的大小

在使用 JPA 和 Hibernate 時,應該始終關註持久性上下文的大小。 出於這個原因,您不應該過多地使用托管實體。 通過限制托管實體的數量,我們可以獲得更好的內存管理,並且默認的檢查機制也將更加高效。

10.只抓取必要的東西

獲取太多的數據可能是導致數據訪問層性能出問題的首要原因。 一個問題是,即使是只讀的 Projections,實體查詢也是專用的。

DTO projections更適合於獲取自定義視圖,而實體只能在業務流需要修改時才能獲取。

EAGER抓取是最糟糕的,您應該避免反模式(Anti-Pattern),例如Open-Session in View。

11.高速緩存

技術分享

關系數據庫系統使用許多內存緩沖區結構來避免磁盤訪問。 數據庫緩存經常被忽視。 我們可以通過適當調整數據庫引擎來顯著降低響應時間,以便工作集駐留在內存中,而不是一直從磁盤中獲取。

應用程序級緩存對於許多企業應用程序來說是不可選的。 應用程序級緩存可以減少響應時間,同時為數據庫關閉以進行維護或由於某些嚴重系統故障提供只讀輔助存儲庫。

二級緩存對於減少讀寫事務響應時間非常有用,特別是在主從復制體系結構中。 根據應用程序的要求,Hibernate允許你在READ_ONLY,NONSTRICT_READ_WRITE,READ_WRITE和TRANSACTIONAL之間進行選擇。

12.並發控制

在性能和數據完整性方面,事務隔離級別的選擇是非常重要的。 對於多請求Web流程,為避免丟失更新,您應該對分離的實體或 EXTENDED 持久性上下文使用optimistic鎖定。

為避免optimistic locking誤報,您可以使用無版本optimistic並發控制或基於讀寫的屬性集來拆分實體。

13.釋放數據庫查詢功能

僅僅因為您使用JPA或Hibernate,並不意味著您不應該使用原生查詢。 您應該利用窗口函數,CTE(公用表表達式),CONNECT BY,PIVOT 查詢。

這些構造允許您避免獲取太多的數據,以便稍後在應用程序層進行轉換。 如果可以讓數據庫進行處理,那麽只能獲取最終結果,因此可以節省大量的磁盤I / O和網絡開銷。 為避免主節點重載,可以使用數據庫復制和擁有多個從屬節點,這樣數據密集型的任務就會在從屬節點而不是主節點上執行。

14.橫向擴展和縱向擴展

關系數據庫的伸縮性非常好。如果Facebook、Twitter、Pinterest或StackOverflow可以擴展他們的數據庫系統,那麽很有可能您可以將企業應用程序擴展到其特定的業務需求。

數據庫復制和分片是提高吞吐量的很好的方法,您應該完全可以利用這些經過測試的架構模式來擴展您的企業應用程序。

結論

高性能數據訪問層必須與底層數據庫系統互相響應。 了解關系數據庫和正在使用的數據訪問框架的內部工作原理可以使企業高性能應用程序和幾乎沒有crawls的應用程序之間產生差異。

歡迎加入學習交流群569772982,大家一起學習交流。

高性能 Java 持久化的 14 個技巧