MySQL使用JPA+Hibernate的9個高性能技巧
介紹
儘管有SQL標準,但每個關係資料庫終將是唯一的,因此你需要調整數據訪問層,以便充分利用在使用中的關係資料庫。
在本文中,我們將介紹在使用帶有JPA和Hibernate的MySQL時,為了提高性能,我們可以做哪些事情。
不要使用AUTO標識符GeneratorType
每個實體都需要標識符,標識符惟一地標識與該實體關聯的表記錄。JPA和Hibernate允許根據三種不同的策略自動生成實體標識符:
- IDENTITY
- SEQUENCE
- TABLE
正如我在這篇文章中所解釋的,當增加資料庫連接數時,TABLE標識符策略不會縮放。而且,即使是一個資料庫連接,標識符生成響應時間比使用IDENTITY或SEQUENCE大十倍。
如果你使用AUTO GenerationType:
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
Hibernate 5將會退回到使用TABLE生成器,這對性能不利。
正如我在這篇文章中所解釋的,你可以使用以下映射輕鬆解決此問題:
@Id
@GeneratedValue(strategy= GenerationType.AUTO, generator="native")
@GenericGenerator(name = "native", strategy = "native")
private Long id;
本地生成器將選擇IDENTITY而不是TABLE。
IDENTITY生成器禁用JDBC批處理插入
MySQL 5.7和8.0都不支持SEQUENCE對象,因此你需要使用IDENTITY。但是,正如我在這篇文章中所解釋的,IDENTITY生成器可以防止Hibernate使用JDBC批量插入。
JDBC批量更新和刪除不受影響,只有INSERT語句不能被批處理,因為在Persistence Context被刷新之前,INSERT語句已被執行,從而Hibernate知道要分配給持久化實體什麼實體標識符。
如果要解決此問題,則必須通過不同的框架,如jOOQ,執行JDBC批處理插入。
通過Docker和tmpfs加速集成測試
MySQL和MariaDB在不得不丟棄資料庫模式的時候,以及每次新的集成測試即將運行因而重新創建它的時候,是非常慢的。但是,你可以在Docker和tmpfs的幫助下輕鬆解決此問題。
正如我在這篇文章中所解釋的,通過映射內存中的數據文件夾,集成測試的運行速度將與有內存資料庫(如H2或HSQLDB)時的速度相同。
對非結構化數據使用JSON
即使是在你使用RDBMS的時候,肯定也有很多次想要存儲非結構化數據:
- 來自客戶端,如JSON的數據,需要被解析並插入到我們的系統中。
- 可以緩存的圖像處理結果以保存再處理
雖然本機不支持,但是你可以輕鬆地將Java對象映射到JSON列。甚至可以將JSON列類型映射到Jackson JsonNode。
更重要的是,你甚至不必編寫這些自定義類型,可以從Maven Central中抓取:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>1.0.0</version>
</dependency>
很酷,對吧?
使用存儲過程來保存資料庫
在處理大量數據時,將所有數據移入和移出資料庫並不是非常高效。不過,通過調用存儲過程對資料庫端進行處理會好很多。
有關更多詳細信息,請參閱這篇有關如何調用帶有JPA和Hibernate的MySQL存儲過程的文章。
小心ResultSet流
SQL流在兩層應用程序中是很有意義的。如果你要執行ResultSet流,那麼你也得注意JDBC驅動程序。在MySQL上,你需要將Statement大小設置為Integer.MIN_VALUE。
然而,對於基於Web的應用程序,分頁更為合適。JPA 2.2甚至引入了對Java 1.8 Stream方法的支持,但執行計劃可能不如使用SQL級別分頁時那麼高效。
PreparedStatements可能會被模擬
你可能以為,既然Hibernate默認使用PreparedStatements,那麼所有語句都是像這樣執行的:
實際上,更像是這樣執行的:
正如我在這篇文章中所解釋的,除非你設置了useServerPrepStmts MySQL JDBC驅動程序屬性,否則PreparedStatements將在JDBC驅動程序級別進行模擬以保存一個額外的資料庫。
始終結束資料庫事務
在關係資料庫中,每個語句都在給定的資料庫事務中執行。因此,事務是不可選的。
但是,你應該始終通過提交或回滾來結束當前正在運行的事務。忘記結束事務可能會導致持續被鎖很長時間,同時也會阻止MVCC清理過程回收不再需要的舊元組或索引條目。
遞交日期/時間沒有那麼容易
編程中有兩件非常複雜的事情:
- 處理編碼
- 處理跨多個時區的日期/時間
為了解決第二個問題,最好在UTC時區中保存所有時間戳。但是,當使用MySQL時,你還需要將useLegacyDatetimeCode JDBC Driver配置屬性設置為false。
結論
正如你所看到的,在使用帶有JPA和Hibernate的MySQL時,要記住許多事情。因為MySQL是最為廣泛部署的RDBMS之一,並被絕大多數的Web應用程序所使用,所以,了解所有這些技巧並調整數據訪問層來最大限度地利用它非常有用。
※關於PHPExcel中日期轉換遇到的一些問題
※RPC框架的原理
TAG:程序員小新人學習 |