性能調優系列前序文章索引:html
今天老兵哥將介紹經過優化對象關係映射 ORM 框架(Hibernate)等來優化系統性能的方法。java
4. ORM 框架 Hibernate程序員
對象-關係映射 ORM(Object/Relation Mapping),是伴隨着面向對象軟件開發方法的發展而產生的。面向對象的開發方法是當今企業級應用開發環境中的主流方法,關係數據庫是企業級應用環境中數據永久存儲的主流數據存儲系統。對象和關係是業務實體數據的兩種表現形式,業務實體在內存中表現爲對象,在數據庫中表現爲關係數據。內存中的對象之間存在關聯和繼承關係,而在數據庫中,關係數據沒法直接表達多對多關聯和繼承關係。數據庫
對象-關係映射 ORM 系統一般以中間件的形式存在,藉助描述對象到關係數據庫數據的映射元數據,將內存中的對象自動持久化到關係數據庫中,其本質就是將數據從一種形式轉換到另一種形式。這個轉換過程須要額外的開銷,天然也就存在許多優化的機會,接下來咱們一塊兒來看看如何提高 ORM 框架 Hibernate 的性能。 緩存
4.1 批量處理session
應用或者 ORM 框架每次執行 SQL 語句都須要跟數據庫創建鏈接,每次創建鏈接都須要額外開銷。若是某個事務內部有循環屢次操做數據庫的場景,那麼將這些操做聚集在一塊兒批量執行,這樣就能夠下降損耗,具體以下:架構
使用這種方法時,首先在 Hibernate 的配置文件 hibernate.cfg.xml 中設置批量尺寸屬性 hibernate.jdbc.batch_size ,且最好關閉Hibernate的二級緩存以提升效率。併發
<hibernate-configuration> <session-factory> <property name="hibernate.jdbc.batch_size">50</property> //設置尺寸 <property name="hibernate.cache.use_second_level_cache">false</property> //關閉緩存 <mapping resource="com/itlaobingge/po/User.hbm.xml" /> </session-factory> </hibernate-configuration>
public class HibernateDemo { public static void main(String args[]) { Session session = HibernateSessionFactory.getSession(); Transaction ts = session.beginTransaction(); for (int i = 0; i < 50; i++) { User user = new User(); user.setPassword(i); session.save(user); if (i%50 == 0) { // 以 50 爲一個批次往數據庫提交,此值應與配置的批量尺寸一致 session.flush(); // 清空緩存區,釋放內存供下批數據使用 session.clear(); } } ts.commit(); HibernateSessionFactory.closeSession(); } }
爲了使 Hibernate 的 HQL 直接支持 update 的批量更新語法,咱們須要在 Hibernate 的配置文件 hibernate.cfg.xml 中設置 HQL/SQL 查詢翻譯器屬性 "hibernate.query.factory_class":app
<hibernate-configuration> ...... <property name="hibernate.query.factory_class"> org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory </property> <mapping resource="com/itlaobingge/po/User.hbm.xml" /> </session-factory> </hibernate-configuration>
public class HibernateDemo { public static void main(String args[]) { Session session = HibernateSessionFactory.getSession(); Transaction ts = session.beginTransaction(); Query query = session.createQuery("update User set password='123456'"); query.executeUpdate(); ts.commit(); HibernateSessionFactory.closeSession(); } }
爲了使 Hibernate 的 HQL 直接支持 delete 的批量更新語法,咱們須要在 Hibernate 的配置文件 hibernate.cfg.xml 中設置 HQL/SQL 查詢翻譯器屬性 "hibernate.query.factory_class":框架
<hibernate-configuration> ...... <property name="hibernate.query.factory_class"> org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory </property> <mapping resource="com/itlaobingge/po/User.hbm.xml" /> </session-factory> </hibernate-configuration>
public class HibernateDemo { public static void main(String args[]) { Session session = HibernateSessionFactory.getSession(); Transaction ts = session.beginTransaction(); Query query=session.createQuery("delete User where id < 123"); query.executeUpdate(); ts.commit(); HibernateSessionFactory.closeSession(); } }
4.2 抓取策略
抓取策略是指當應用程序須要在對象關聯關係間進行導航時,Hibernate 如何獲取關聯對象的策略,常見的抓取策略有以下幾種:
Hibernate 會區分下列幾種狀況:
定製合理的抓取策略對系統的性能提高有很大的幫助。查詢抓取在 N+1 查詢的狀況下是極其脆弱的,所以咱們可能會要求在映射文件中定義鏈接抓取(fetch=」join」),可是在映射文件中定義的抓取策略將會產生如下影響:經過 get() 或者 load() 方法獲取數據,只有在關聯之間進行導航時,纔會隱式的取得數據。
條件查詢,使用了 subselect 抓取的 HQL 查詢,無論使用哪一種抓取策略,定義爲非延時的類圖會保證裝載入內存,這就意味着一條 HQL 查詢後緊跟着一系列的查詢。一般咱們並不使用映射文件進行抓取策略的定製,更可能是保持其默認值而後在待定事務中適用 HQL 的左鏈接對其進行重載。
Hibernate 推薦的作法也是最佳實踐:把全部對象關聯的抓取都設爲 lazy,而後在特定事務中進行重載。這種考慮是基於對象之間的關聯關係錯綜複雜,有時候哪怕咱們只是一個簡單的查詢,也會致使不少關聯對象被裝載出來,因此在 Hibernate 中,全部對象關聯都是 lazy 的。
在 Hibernate 中實施關聯抓取,咱們能夠定義每次抓取數據的數量,批量地將數據載入內存,減小與數據庫交互的次數,在應用程序中能夠定義默認的關聯抓取數量。Hibernate 提供了兩種批量抓取方案:
<class name=」Class」 batch-size=」15」>...</class>
<set name=」users」 batch-size=」15」>...</set>
4.3 二級緩存
緩存能夠下降應用程序對物理數據源訪問的頻次,從而提升應用程序的運行性能。緩存對 Hibernate 來講也是很重要的,它使用了以下圖所示的多級緩存方案:
Hibernate 的二級緩存經過兩個步驟設置:
4.4 查詢緩存
查詢結果集也能夠被緩存,只有在常用一樣的參數進行查詢時,查詢緩存纔會有些用處。若是要使用查詢緩存,你必須打開它:hibernate.cache.use_query_cache,該設置將會建立兩個緩存區域:一個用於保存查詢結果集(org.hibernate.cache.StandardQueryCache);另外一個則用於保存最近查詢的一系列表的時間戳(org.hibernate.cache.UpdateTimestampsCache)。
在查詢緩存中,它並不緩存結果集中所包含的實體的確切狀態,它只緩存這些實體的標識符屬性的值、以及各值類型的結果,因此查詢緩存一般會和二級緩存一塊兒使用。絕大多數的查詢並不能從查詢緩存中受益,因此 Hibernate 默認是不進行查詢緩存的。如若須要進行緩存,請調用 Query.setCacheable(true) 方法。這個調用會讓查詢在執行過程當中時先從緩存中查找結果,並將本身的結果集放到緩存中去。
關注「 IT老兵哥 」,賦能程序人生!堅持原創不易,請小夥伴們不吝點個「 贊 」哦!推薦軟技能文章,請點擊連接:程序員,怎樣打造我的影響力?
近期熱評系列《 程序員必須懂的架構師入門課 》:
原文出處:https://www.cnblogs.com/itlaobingge/p/12221003.html