另一種更先進的長期緩存的方法是通過將weblogic-ejb-jar.xml中的cache-between-transactions元素設置為 true來配置bean。這種情況下,只有客戶端首先引用該bean或者事務被回滾時WebLogic Server才會調用ejbLoad()來從數據庫中加載數據。
盡管從理論上說,您可以對除數據庫并發之外的所有并發策略使用該方法,但是在實踐中,只有對樂觀并發使用該方法才有意義。當應用于只讀并發時,該設置被忽 略,因為bean數據已經被緩存;當應用于排他性并發時,只有EJB具有對底層數據庫的排他性訪問時才起作用,而這是極少出現的情況。此外,當具有排他性 并發的bean被部署在集群中時,WebLogic Server自動禁用事務間的緩存,因為集群中的任何服務器都可能更新bean數據,并且沒有用來在節點間同步或禁用緩存值的機制。這使得我們在進行長期 緩存時只有一種可行的并發策略:樂觀并發。
如前所述,對于利用樂觀并發策略部署的bean,WebLogic Server有一種內在機制,用來通過verify-columns檢測底層數據變更。雖然樂觀并發本身只能為數據庫并發帶來少量性能改善,但可利用事務 功能間的緩存提供更大的改善。如果在EJB緩存中bean實例已經可用的話,將cache-between-transactions設置為true將使 WebLogic Server忽略對數據庫的調用。對于某些類型的應用程序(其中同一對象在短期內被不同事務多次訪問),這可能導致顯著的性能改善(在某些環境下,最多百 分之30到40)。自然地,既然我們使用的是樂觀并發,您的應用程序必須做好在檢測到并發沖突時處理 OptimisticConcurrencyException的準備。當 OptimisticConcurrencyException(RuntimeException的子類型)被拋出時,WebLogic Server 從緩存中丟棄一個EJB實例。注意,如果您將delay-updates-until-end-of-tx設置為true(默認),除非事務承諾否則就得 不到樂觀異常,并且如果使用的是容器受控事務這將在應用程序代碼之外。
與read-mostly模式(不提供通知集群中其他節點其中一個節點的數據發生變更的機制)相比,當具有樂觀并發的bean被更新時,一個通知將被廣播 給其他集群成員,并且緩存bean實例將被丟棄,以避免樂觀沖突。由于WebLogic Server不廣播數據變更本身,而是只廣播某些種類的bean標識符,這種跨集群的緩存無效措施在提高性能和網絡帶寬利用率方面很有效。 WebLogic Server自動完成這種緩存無效工作,bean開發人員不需要再做其他配置。當對同一個bean發出下一個請求時,新鮮的數據將被從數據庫中加載。
If the data in the database is updated by processes external to the server (or if you're using direct JDBC aclearcase/" target="_blank" >ccess from the server to modify the same tables as mapped to CMPs with long-term caching), then these processes should honor the contract on version columns. 換言之,如果實體bean被配置為使用數值版本列,那么外部進程應該在行數據更新時增加該值;如果使用了一個時間戳列,那么這個值應該被 更新為當前時間戳。如果不這樣做會導致WebLogic Server覆蓋數據,因為它的樂觀檢測機制不會觸發異常,如果版本數據沒有被更改的話。如果不可能通過修改外部進程來更新版本列,可用數據庫觸發器來實 現同樣效果。如果不允許修改數據庫模式,可對WebLogic Server進行配置,使其檢查事務期間被讀取的所有列或者只讀取更新過的列(通過分別將verify-columns元素設置為Read或 Modified來實現)。注意,這種情況下,可能存在性能問題,因為生成的更新SQL語句更復雜。我建議進行測試,以確定這會對您具體環境中的更新造成 多大影響。
在事務間進行緩存提供了比上面討論過的read-mostly模式更好的緩存數據模型。首先,并沒有增加復雜度,比如部署同一bean的兩個版本。另外, 對啟動時間,以及當集群間bean發生變更時的自動緩存禁用等也沒有造成影響。直到最近,WebLogic Server中與事務bean間緩存相關的一項特性還被忽視。沒有公開的機制來有計劃地使bean緩存無效。如果您對服務器上數據庫進行排他性訪問,這沒 有什么大問題,但是在很多項目中,很少有這種情況,并且為了清空緩存,必須重啟實例;同樣,這也并不總是可能的。
讓我們看一下如果一個bean用樂觀并發部署并且當數據庫中的數據被外部進程更新時被在事務間緩存,這時會發生什么。如果一個外部進程更新當前被容器緩存 的記錄,然后應用程序通過CMP更新同樣的列,那么會有兩種可能的結果:如果外部進程在更新verify-columns時不遵守協定,那么就會出現更新 丟失的情況(來自CMP的更新覆蓋外部進程對記錄進行的修改)。另一方面,如果外部進程更新了版本列,或者bean被配置,以便用 Read/Modified列進行樂觀控制,您就可能有一個OptimisticConcurrencyException。
在WebLogic Server中,OptimisticConcurrencyException是RuntimeException的一個子類,并且如果應用程序沒有捕 獲它,實體實例(以及調用同一事務中該實體的所有會話bean)就被丟棄,事務就被回滾;下一次,WebLogic Server會從數據庫中重新加載數據,并且事務會成功完成。盡管缺乏“美感”,但這種方法對于使用隊列(MOM)的應用程序來說還是很有效的;在事務回 滾時,該消息將保留在隊列中,接著下一個重新交付嘗試(如果有的話)會成功。值得再次一提的是,除非您的應用程序使用bean受控事務,否則您將捕獲不到 OptimisticConcurrencyException,除非將delay-updates-until-end-of-tx設為false(非 默認值)。利用默認設置,WebLogic Server不能在數據庫中執行實際的DML操作,并且操作會以RollbackException(它內部就是提到過的真正的 OptimisticConcurrencyException)異常而失敗。
原文轉自:http://www.anti-gravitydesign.com