構建高性能Java持久層的14個建議

Introduction

一個高性能的數據訪問層須要不少關於數據庫的內部結構、JDBC、JPA、Hibernate以及不少優化商業應用的技術建議。git

SQL Statement Logging:SQL語句日誌

若是你正在使用譬如Hibernate或者MyBatis這樣的ORM框架,那麼能夠參考驗證執行語句的效率。另外推薦一個 測試中斷言機制 能夠幫你在提交代碼以前就發現不少的查詢問題。github

Connection management:鏈接管理

數據庫鏈接一直是數據庫中比較耗時的操做,所以建議是務必使用數據庫鏈接池 機制。另外,數據庫鏈接還受到數據庫底層的限制,所以也須要合理有效地釋放無用的數據庫鏈接。在性能調優中,咱們常常須要測試而且設置合理的鏈接池大小。這裏推薦一個FlexyPool工具能夠幫助你選擇生產環境下合適的鏈接池大小。sql

JDBC Batching:批量JDBC操做

JDBC Batching容許在單次數據庫鏈接中發送多個SQL語句。這篇博客裏進行了對比能夠看出Batch操做的性能提高很是巨大 ,不管是在客戶端仍是數據庫端。 PreparedStatements 是不錯的用於Batching操做的選擇,像Oracle也僅支持基於PreparedStatements的Batching操做。數據庫

JDBC中已經基於PreparedStataement.addBatchPreparedStataement.executeBatch)提供了Batching操做的輔助,不過若是打算手動的構造Batching操做,那麼在設計階段就要考慮到是否須要引入Batching。若是你用的是Hibernate,那麼能夠用簡單的配置就開啓Batching,Hibernate 5.2 提供了 Session級別的Batching, 也是很是方便的。json

Statement Caching:語句緩存

Statement Caching算是最不經常使用的幾種優化手段之一了,你能夠利用PreparedStatements同時在客戶端(Driver)或者數據庫端同時緩存語句。api

Hibernate Identifiers

若是你是使用Hibernate做爲ORM工具,那麼IDENTITY生成器可能會影響到你的性能,由於它會禁止掉JDBC Batching。Table生成器也不是啥好選擇,它會使用獨立的事務上下文進行捕獲操做,而致使底層的事務日誌承受額外的壓力,而且致使了每次鏈接池中的新的請求都須要一個新的Identifier。所以筆者仍是推薦SEQUENCE生成器,SQL Server在2012版本以後也開始支持了該生成器。緩存

選擇合適的列類型

在數據庫設計的時候,咱們應該儘量地選用合適的列類型,這樣可讓你的數據庫以最合適的方式去索引存儲你的數據。譬如在PostgreSQL中你應該使用inet來存放IPv4的地址,特別是Hibernate還容許你自定義數據類型,這樣方面和數據庫中的列類型一一對應。性能優化

Relationships:映射關聯

Hibernate提供了不少的關係映射,不過並非全部的映射都是性能優化的。

咱們在開發的過程當中須要注意避免單向的關係映射,以及@ManyToMany這種映射。對於集合查詢而言,雙向的@OneToMany關係纔是值得推薦的。

Inheritance:繼承

繼承是面向對象的語言中的不可或缺的一部分,但這也是關係型數據庫與面向對象的語言之間的不協調最甚的地方。JPA提供了譬如SINGLE_TABLEJOIN以及TABLE_PER_CLASS來處理繼承映射的問題,而這幾個辦法都是各有千秋。

  • SINGLE_TABLE在SQL語句中的表現最好,不過不能使用NOT NULL約束,數據完整性的控制較差。

  • JOIN 經過更復雜的語句控制來保證了數據的完整性,只要你不使用多態查詢或者@OneToMany關係註解,那一切還好。

  • 應該避免使用TABLE_PER_CLASS,它基本上沒法生成高效的SQL語句。

Persistence Context Size:持久化上下文的大小

在使用JPA或者Hibernate時候,應該隨時注意持久化上下文的大小,避免同時管理過多的實體類。經過限制受管實體類的數量,咱們能夠更好地進行內存管理,而默認的髒檢測機制也會有更好的效果。

只獲取必要的數據

獲取過多的冗餘數據多是致使數據訪問層性能降低的緣由之一,即便是包含了投影等操做,對於實體的查詢應該也是排外的,即不會引入冗餘數據的。咱們應該只獲取那些業務邏輯須要到的數據,這裏推薦使用DTO Projections。過早的數據獲取以及Open Session In View這種反模式都是要被避免的。

Caching:緩存

關係型數據庫使用了不少的內存緩衝結構體來避免大量的磁盤訪問,可是咱們每每忽略了數據庫緩存。咱們能夠經過調整數據庫查詢引擎,將更多的內容留於內存中以免磁盤查詢最終明顯的減小響應耗時。應用層的緩存則利用高速副本的方式來保證低響應時間。而Second-Level緩存可以有效減小讀寫事務的響應時間,特別是在主從複製架構中。根據不一樣的應用取錢,Hibernate提供了 READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, 以及 TRANSACTIONAL這幾種方式。

Concurrency Control:併發控制

在考慮性能和數據完整性的時候,事務隔離層 就變得相當重要。對於併發較高的應用,須要避免更新失敗, 可使用 樂觀鎖或者擴展的持久化上下文.

而爲了不 樂觀鎖中的 false positives, 可使用 無版本的樂觀控制或者基於寫屬性集的實體劃分.

提升數據庫查詢能力

雖然你是用了JPA或者Hibernate,可是你能夠用一些原生查詢,建議是好好利用Window Functions, CTE (Common Table Expressions), CONNECT BY, PIVOT等等。這些工具可以避免你一次性傳輸過多的數據進入應用層,若是你能夠把這個操做託付給數據庫層進行,那麼能夠僅關心最終的結果,從而節約了磁盤IO與網絡帶寬。

集羣擴展

關係型數據庫可以方便地進行擴展,像Facebook、Twitter、Pinterest這些大公司都擴展了數據庫系統:

數據副本與分片是兩種經常使用的增長吞吐量的擴展方式,你應該合理的組合應用這些方式從而提升你的商業應用的能力。

相關文章
相關標籤/搜索