歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Hibernate數據修改後不能及時更新

Hibernate數據修改後不能及時更新

日期:2017/3/1 9:40:14   编辑:Linux編程

主要表現在新增、修改數據後,在數據列表中不能顯示剛插入數據的關聯對象的信息(新增插入或修改的數據主數據能顯示,只有關聯的數據不能顯示),但刷新後能顯示,再刷新可能又顯示不出來了。隨機的能顯示或不能顯示。搞不懂。

當你手動修改了數據庫,Hibernate緩存中的數據就有可能是過期的。為了保證Hibernate與數據庫一致,一般的做法是在手動修改數據庫之後,使用Hibernate查詢數據之前,清空緩存。也就是說,你應該在執行查詢前,調用session.clear().

Hibernate整體理解 http://www.linuxidc.com/Linux/2014-07/104405.htm

Hibernate工作機制及其常用類和方法 http://www.linuxidc.com/Linux/2011-12/50419.htm

hibernate緩存管理

1.緩存概述

緩存(cache)在java應用程序中是一組內存中的集合示例,它保存著永久性存儲源(如硬盤上的文件或數據庫)中數據的備份,它的讀寫速度比讀寫硬盤的速度快。應用程序在運行時直接讀寫緩存中的數據,只在某些特定時刻按照緩存中的數據來同步更新數據存儲源。如果緩存中存放的數據量非常大,也會用硬盤作為緩存的物理介質

緩存的作用就是降低應用程序直接讀寫永久性數據存儲源的頻率,從而增強應用的運行性能

緩存的實現不僅需要作為物理介質的硬件(內存),同時還需要用於管理緩存的並發訪問和過期等策略的軟件

2.緩存范圍分類

緩存的范圍決定了緩存的聲明周期以及可以被誰訪問。總共分三類

1)事務范圍

事務范圍的緩存只能被當前事務訪問,每個事務都有各自的緩存,緩存內的數據通常采用相互關聯的對象形式.緩存的生命周期依賴於事務的生命周期,只有當事務結束時,緩存的生命周期才會結束.事務范圍的緩存使用內存作為存儲介質,一級緩存就屬於事務范圍.

2)應用范圍(也叫進程范圍)

應用程序的緩存可以被應用范圍內的所有事務共享訪問.緩存的生命周期依賴於應用的生命周期,只有當應用結束時,緩存的生命周期才會結束.應用范圍的緩存可以使用內存或硬盤作為存儲介質,二級緩存就屬於應用范圍.

3)集群范圍

在集群環境中,緩存被一個機器或多個機器的進程共享,緩存中的數據被復制到集群環境中的每個進程節點,進程間通過遠程通信來保證緩存中的數據的一致,緩存中的數據通常采用對象的松散數據形式.

對大多數應用來說,應該慎重地考慮是否需要使用集群范圍的緩存,因為訪問的速度不一定回避直接訪問數據庫數據的速度快很多

3.緩存的並發訪問策略

當多個並發的失誤同時訪問持久化層的緩存的相同數據時,會引發起並發問題,必須采用必要的失誤隔離措施

在進程范圍或集群范圍的緩存,會出現並發問題,因此可以設定一下四種類型的並發訪問策略,每一種策略對應一種事務隔離級別。事務型並發訪問策略是事務隔離級別最高,只讀型的隔離級別最低。事務隔離級別越高,並發性能就越低

 1)事務型:僅僅在受管理環境中適用。它提供了Repeatable Read事務隔離級別。對於經常被讀但很少修改的數據,可以采用這種隔離類型,因為它可以防止髒讀和不可重復讀這類的並發問題。

 2)讀寫型:提供了Read Committed事務隔離級別。僅僅在非集群的環境中適用。對於經常被讀但很少修改的數據,可以采用這種隔離類型,因為它可以防止髒讀這類的並發問題。

 3)非嚴格讀寫型:不保證緩存與數據庫中數據的一致性。如果存在兩個事務同時訪問緩存中相同數據的可能,必須為該數據配置一個很短的數據過期時間,從而盡量避免髒讀。對於極少被修改,並且允許偶爾髒讀的數據,可以采用這種並發訪問策略。   

4)只讀型:對於從來不會修改的數據,如參考數據,可以使用這種並發訪問策略。

Hibernate中的緩存

hibernate中提供兩級緩存,第一級別是Session級別的緩存,它是屬於事務范圍的緩存,第二級別的緩存是SessionFactory級別的緩存,它是屬於進出呢個范圍或集群范圍的緩存。這一級別的緩存可以進行配置和更改,並且可以進行動態的加載和卸載。Hibernate還為查詢結果提供了一個查詢緩存,它依賴於第二級緩存

一級緩存的管理:

Hibernate的一級緩存是由Session提供的,因此它只存在於Session的生命周期中,當程序調用save(),update(),saveorupdate()等方法 及調用查詢接口list,filter,iterate時,如session緩存中還不存在相應的對象,Hibernate會把該對象加入到一級緩存中,
當Session關閉的時候該Session所管理的一級緩存也會立即被清除
Hibernate的一級緩存是Session所內置的,不能被卸載,也不能進行任何配置

一級緩存采用的是key-value的Map方式來實現的,在緩存實體對象時,對象的主關鍵字ID是Map的key,實體對象就是對應的值。所以說,一級緩存是以實體對象為單位進行存儲的,在訪問的時候使用的是主關鍵字ID
雖然,Hibernate對一級緩存使用的是自動維護的功能,沒有提供任何配置功能,但是可以通過Session中所提供的方法來對一級緩存的管理進行手工干預。Session中所提供的干預方法包括以下兩種
●evict() :用於將某個對象從Session的一級緩存中清除
evict()方法適用於以下二種情況:
1)不需要該對象進行同步的數據更新
2)在批量進行更新與刪除時,當更新刪除每一個對象後,要釋對此對象所占用的內存.

●clear() :用於將一級緩存中的所有對象全部清除。</p>

<p> 在進行大批量數據一次性更新的時候,會占用非常多的內存來緩存被更新的對象。這時就應該階段性地調用clear()方法來清空一級緩存中的對象,控制一級緩存的大小,以避免產生內存溢出的情況。
Hibernate大批量更新時緩存的處理方法:
(假設我們user表的age有5000條大於0的記錄,)
Session session =SessionFactory.openSession();
Transaction tx =session.beginTransaction();
Itertaor users=session.find("from User u where u.age>0").itertaor();//HSL語句就不做解釋了
while(user.hasNext()){
User user =(User)users.next();
user.setAge(user.getAge()+1);
//將本批插入的對象立即寫入數據庫並釋放內存
session.flush();
session.clear();
}
tx.commit();
session.close();
用Hibernate處理大批數據時..都必須先執行5000次的update語句,然後才能更新5000個user 對象..
這樣就影響到了操作上的性能....在項目當我們遇到性能與空間的問題時,,,要以性能為主..這也就是說要犧牲空間

所以程序最好跳過Hibernate API 而直接通過JDBC API來執來...

我們改一下上面的代碼:
Session session=SessionFactory.openSession();
Transaction tx =session.beginTransaction();
Connection conn =session.connection();
PreparedStatement pstmt = conn.prepareStatement("update users set age=age+1 "+"where age >0");
pstmt.executeUpdate();
tx.commit();
雖說這是通過JDBC API搞作的..但本質上還是通過Hibernater Transaction的事務這個接口來聲明事務的邊界的...

其實最好的解決方法就是以創建存儲過程,,用底層的數據庫運行..這樣性能好,速度快....

我就簡單的以Oracle數據庫為例子.創建一個名為UserUpdate的存儲過程...然後在程序中進行調用...
UserUpdate的存儲過程代碼:
create or replace procadure UserUpdate(u_age in number) as
begin
update users set age=age+1 where age>u_age;
end;
下面的是在程序中如何調用我們命名的存儲過程
Session session =SessionFactory.openSession();
Transaction tx =session.beginTransaction();
Connection conn=session.connection();
String str="{call UserUpdate(?)}";
CallableStatement cstmt= conn.prepareCall(str);
cstmt.setInt(1,0);
cstmt.executeUpdate();
tx.commit(); 注意.開源的MySQL中不支持存儲過程的..
用JDBC API的好處是這樣的..
它不用把大批量的數據事先加載到內存中,然後再進行更新與修改..所以不會消耗大量內存....
(小程序中是看不出什麼差別的..當數據的記錄達到一定的數據量的時候自然會發現用Hibernate API 與JDBC API的差別)
在一個就是只能一條記錄進行批量更新..不像Hibernate中更新每一條的..

第一級是Session的緩存。由於Session對象的生命周期通常對應一個數據庫事務或者一個應用事務,因此它的緩存是事務范圍的緩存。第一級緩存是必需的,不允許而且事實上也無法比卸除。在第一級緩存中,持久化類的每個實例都具有唯一的OID。

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-09/106458p2.htm

Copyright © Linux教程網 All Rights Reserved