首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Spring Web Flow 2 流管理持久化詳解:事務性 Web 流的持久化策略與最佳實踐

     編輯:Java 相關知識

JPA/Hibernate 持久化上下文挑戰

傳統 Web 應用中,實體在視圖渲染階段若已分離(持久化上下文關閉),訪問延遲加載關係會拋出 LazyInitializationException。Open Session in View 模式雖能解決,但將持久化上下文綁定到請求作用域,導致跨請求的實體需重新附著/合併,增加複雜度。

流管理持久化核心機制

Spring Web Flow 採用流作用域持久化上下文:在流啟動時創建 EntityManager/Session 並綁定到流作用域,整個流程複用同一上下文。實體在多請求間保持持久狀態,避免分離問題。變更作為髒實體緩存,直到流結束時才 flush() 並提交事務(原子流),或每步提交(非原子流)。

持久化上下文類型選擇

  • 事務型(TRANSACTION,默認):注入的共享代理,委託給綁定線程的流作用域上下文。必須使用此類型。
  • 擴展型(EXTENDED):非線程安全,不可用於單例 Bean,會導致不可預測行為,嚴禁用於流作用域。

這與 Seam 對話(常用擴展型 EntityManager 注入狀態 Session Bean)有本質區別。

事務語義與 @Transactional 配置

@Transactional 可調整流持久化特徵。默認語義:

@Transactional(readOnly=false, propagation=REQUIRED, isolation=ISOLATION_DEFAULT, timeout=TIMEOUT_DEFAULT)
  • readOnly=false:讀寫事務,FlushMode=AUTO
  • readOnly=true:只讀事務,FlushMode=MANUAL(需 Hibernate 支援,JPA 1.0 不支援)
  • propagation:事務傳播行為
  • isolation:JPA 1.0 不支援自定義,需資料庫端配置 Read-Committed 以上

原子 Web 流處理策略

非事務性數據訪問(默認)

流中所有數據訪問預設非事務性。Hibernate 設 auto-commit=true、FlushMode=MANUAL。實體由流作用域上下文管理,變更緩存為髒狀態。流結束時:

  • <end-state commit="true"/>:隱式 flush() 並提交
  • <end-state commit="false"/>:捨棄變更

此方式符合 JPA 1.0 對話處理規範,由 JpaFlowExecutionListener 實現。

只讀事務策略

全局套用 @Transactional(readOnly=true)(如 Hotel Booking 範例)。行為與非事務性類似,僅在流結束提交時刷新。優勢:防止服務層讀寫事務導致提前刷新。若服務層暴露為 Web Service 並標註 @Transactional,非事務性上下文會被覆蓋,觸發提前 flush;視圖層用 readOnly=true 可覆蓋服務層設定,保持只讀狀態。

事務傳播特殊規則

Spring Web Flow 規定:事務初始化為只讀則始終只讀,反之亦然,忽略後續方法的 readOnly 屬性。

非原子 Web 流處理策略

適用於長期運行流程(BPM)或無固定順序的頁面組群。事務作用域縮小到每個用戶操作(<transition>),而非整個流。

事務邊界指定

SWF 標籤不支援事務劃界,需在 @Transactional Bean 方法中發起,從 <evaluate> 調用。建議:

  • 同一 <transition> 下所有寫操作放入單一 @Transactional 方法,綁定同一事務
  • 避免同一請求多個讀寫事務(非原子,災難性)
  • 只讀操作三選一:非事務性 / readOnly=false(FlushMode=AUTO) / readOnly=true(FlushMode 切換)

Hibernate 團隊建議統一用讀寫事務簡化編程。

樂觀鎖與版本刷新陷阱

非原子流強烈建議用樂觀鎖。實體更新後必須顯式查詢刷新 @Version 字段,否則後續事務更新同一實體會拋 OptimisticLockingFailureException(即使無併發)。這與原子流必須避免更新後查詢(會導致提前刷新)形成鮮明對比。

無流作用域上下文的持久化編程痛點

事務作用域上下文

注入的上下文綁定到事務,跨請求實體分離。Hotel Booking 範例中 cancelBooking 需重新載入實體(em.find())才能刪除。視圖渲染階段延遲讀取會拋 LazyInitializationException。

調用作用域上下文(最差)

非事務性訪問時,每次方法調用返回不同 EntityManager 實例,即時開關,實體無法跨調用保持持久狀態。

跨流傳遞實體

實體離開原流即分離,需合併/重新載入到目標流上下文。

總結:高效安全管理事務的指導原則

  1. 首選流作用域持久化上下文(加 <persistence-context/>)
  2. 原子流:全局套用 @Transactional(readOnly=true)
  3. 非原子流:全局套用 @Transactional(readOnly=false),每操作一事務,更新後刷新版本
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved