標籤:數字 ehcache log fetch 命中 category 擴充 left join update
效能最佳化
1.注意session.clear() 的運用,尤其在不斷分頁的時候
a) 在一個大集合中進行遍曆,遍曆msg,取出其中額含有敏感字樣的對象
b) 另外一種形式的記憶體流失( //面試題:Java有記憶體流失嗎?文法層級沒有,但是可由java引起,例如:串連池不關閉,或io讀取後不關閉)
2.1+N 問題(典型的面試題)
舉例:當存在多對一關聯性時,多的一方預設是可以取出一的一方的
@ManyToOne 中 預設為fetch=FetchType.Eager
當load多的一方時,也會載入一的哪一方,會造成執行不必要的SQL語句
解決辦法,以下幾種:
a) @ManyToOne(fetch=FetchType.LAZY)
//當多對一(@ManyToOne)已經設定屬性" fetch=FetchType.LAZY "時
//只有當需要時(如:t.getCategory().getName()時)才會去擷取關聯表中資料 可以解決N+1問題
b) @BatchSize
//在與查詢表(此例中為Topic類)關聯的表類(此例中為Category類)頭處加@BatchSize(size=5)
//表示每次可查出5條記錄 從而減少了select語句的個數
c) join fetch
//修改hql語句為--" from Topic t left join fetch t.category c
d) QBC
//原理和上面那條是一樣的,使用QBC的 createCriteria(*.class)執行查詢 也可避免N+1問題
3.list 和 iterate 不同之處( //主要為了面試)
a) list 取出表中所有資料構成對象
b) iterate 先取ID,等用到的時候再根據ID 來取對象
c) session 中list 第二次發出,仍回到資料庫查詢
d)iterate 第二次,會先去找 session 緩衝
Hibernate 緩衝機制
前面Hibernate中持久化對象的三種狀態有提到,處於Persistent狀態的對象的標誌是 緩衝中也有這個對象
緩衝中類似於一個一個的索引值對,key 為 id,然後value為這個緩衝的對象
當想要對該對象進行讀寫時,會先去查緩衝,
/*一級緩衝和二級緩衝和查詢快取*/
一級緩衝:session級的緩衝,每個session擁有自己的session緩衝,不同session的session緩衝不能共用
二級緩衝:sessionFactory級的緩衝,所有的session都可以去訪問二級緩衝
查詢快取:相同的SQL語句只執行一次
當緩衝的對象 1.經常被訪問 2.不會經常改動 3.數量不大 時使用二級緩衝
開啟二級緩衝(兩步):
1.在 hibernate.cfg.xml中設定:
1 <property name= "cache.use_second_level_cache">true</property>2 <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
[email protected] 註解 (由hibernate擴充提供)
@Cache (usage=CacheConcurrencyStrategy.READ_WRITE)
(為某個類開啟二級緩衝,針對該類的對象進行的 讀寫操作,會建立二級緩衝)
註:使用EhCache 二級緩衝需要匯入 ehcache-1.2.3.jar 及 commons-logging-1.0.4.jar 包
註:
1.load 預設使用二級緩衝,iterate 預設使用二級緩衝
2.list 預設往二級緩衝加資料,但是查詢的時候不使用
意思是:session.createQuery("from Category").list(); 會將查出來的資料加到緩衝中,但是不會去緩衝中查詢
3.可以使用<property name="hibernate.cache.use_query_cache">true</property>來開啟查詢快取,預設為關閉,
查詢快取來標識某個查詢使用緩衝,當執行同一條SQL語句時,就不會再去資料庫找,也是從緩衝中去找該語句
在開啟了查詢快取之後,需要注意,調用query.list()操作之前,必須顯示調用query.setCacheable(true)
例如:session.createQuery("from Category").setCacheable(true).list();
註:查詢快取只對query.list()起作用,query.iterate不起作用,也就是query.iterate不使用
4.緩衝演算法(新的緩衝對象要進來,怎麼替換):(面試)
LRU LFU FIFO
1.Least Recently Used 最近最少使用的被替換
2.Least Frequently Used 命中率高低 使用頻率最低的被替換
3.First In First Out 按順序替換
在ehcache.xml中配置 memoryStoreEvictionPolicy="LRU"
事務並發處理
a) 事務:ACID
Atomic Consistency Itegrity Durability
b) 事務並發時可能出現的問題:
1.髒讀 (讀到了另一個事務在處理中還未提交的資料)
2.不可重複讀取 (在事務A的執行過程中,事務B進行了開啟,對列中的資料進行修改和提交,
導致事務A在事務B執行前讀取的資料和事務B執行後讀取的資料不一致)
3.虛讀 (在查詢某一條件的資料時,開始查詢後,別人又加入或刪除某些資料,再讀取時與原來的資料不一樣了,
和 不可重複讀取 類似,不過不可重複讀取針對的列裡面資料的修改,而幻讀針對的是列整體的增刪)
c) 資料庫事務的隔離等級
1------read-uncommitted
2------read-committed
4------repeatable read
8------serializable
前面的數字為Hibernate的交易隔離等級對應的數字
為什麼要使用1 2 4 8 而不是 1 2 3 4
1=0000 2=0010 4=0100 8=1000 位元運算效率高
read-uncommitted(允許讀取未提交的資料) 會出現dirty read, phantom-read, non-repeatable read 問題
read-commited(讀取已提交的資料 項目中一般都使用這個)不會出現dirty read,
因為只有另一個事務提交才會讀出來結果,但仍然會出現 non-repeatable read 和 phantom-read
/*使用read-commited機制可用悲觀鎖 樂觀鎖來解決non-repeatable read 和 phantom-read問題*/
repeatable read(事務執行中其他事務無法執行修改或插入操作 較安全)
serializable 解決一切問題(順序執行事務 不並發,實際中很少用)
如何設定Hibernate 的交易隔離等級(使用hibernate.connection.isolation配置 取值1、2、4、8)
1.hibernate.connection.isolation = 2 (如果不設 預設依賴資料庫本身的層級)
2.用悲觀鎖解決repeatable read的問題(依賴於資料庫的鎖(select... for update))
hibernate使用Load進行悲觀鎖加鎖 session.load(Inventory.class, 1, LockMode.UPGRADE); 在產生select語句時,會加上for update 進行使用悲觀鎖
a)LockMode.None 無鎖的機制,Transaction結束時,切換到此模式
b)LockMode.read 在査詢的時候hibernate會自動擷取鎖
c)LockMode.write insert update hibernate 會自動擷取鎖
d)以上3種鎖的模式,是hibernate內部使用的(不需要設)
e)LockMode.UPGRADE_NOWAIT 是 ORACLE 支援的鎖的方式
3.樂觀鎖(其實不是鎖,是一種衝突檢測機制)
實體類中增加version屬性 (資料庫也會對應產生該欄位初始值為0),並在其get方法前加入 @Version 註解
則在操作的過程中每更新一次該行資料則version值 加 1,即可在事務提交前判斷該資料是否被其他事務修改過
(提交事務時,通過對比記憶體中的version值和資料庫中的version值)
註:樂觀和悲觀的區別:
1.悲觀鎖比較悲觀,覺得會有並發的情況發生,所以提前加了一把鎖,
2.樂觀鎖比較樂觀,不著急加鎖,而是先判斷是否出現了並發訪問的情況,如果出現了,再做相應的處理
8.Hibernate效能最佳化