Spring in Action 學習筆記—第五章交易管理
來源:互聯網
上載者:User
Spring in Action
學習筆記
—
第五章
交易管理 本章是第四章的延續,作者向讀者展示了如何使用Spring交易管理來保證資料一致性。Spring對事務的管理有豐富的支援,程式控制的和聲明式的都有。在本章中,我們會學習到如何把應用程式的代碼放置在事務中,以確保在一切順利時,所有的成果都被固定下來;一旦其中有一步出錯,那麼整個事情就像沒有發生一樣。
一、理解事務 首先我們應該弄清楚什麼是事務,這樣才能認識到事務的重要性。舉一個小小的例子,大概每個人都有轉賬的經曆。當我們從A帳戶向B帳戶轉100元後,銀行的系統會從A帳戶上扣除100而在B帳戶上加100,這是一般的正常現象。但是一旦系統出錯了怎麼辦呢,這裡我們假設可能會發生兩種情況:(1)A帳戶上少了100元,但是B帳戶卻沒有多100元。(2)B帳戶多了100元錢,但是A帳戶上卻沒有被扣錢。這種錯誤一旦發生就等於出了大事,那麼再假如一下,你要轉賬的是1億呢。所以上面的兩種情況分別是你和銀行不願意看到的,因為誰都不希望出錯。那麼有沒有什麼方法保證一旦A帳戶上沒有被扣錢而B帳戶上也沒有被加錢;或者A帳戶扣了100元而B帳戶準確無誤的加上100元呢。也就是說要麼轉賬順利的成功進行,要麼不轉賬呢。可以,這就是資料庫事務機制所要起到的作用和做的事情。 下面給出事務的概念(在資料庫中事務的概念在表述上略有差異,但是含義都是一樣的): 所謂
事務是使用者定義的一個資料庫操作序列。這些操作要麼都做,要麼都不做,是一個不可分割的工作單位。事務具有四個特性: 1.
原子性:一個事務中所有對資料庫的操作是一個不可分割的操作序列。這些操作要麼完整的被全部執行,要麼一步也不做。是一個邏輯工作單位。 2.
一致性:一個事務獨立執行的結果將保持一致性,即資料不會因為事務的執行而遭受破壞。 3.
隔離性:一個事務的執行不能被其他事務幹擾。即一個事務內部的操作及使用的資料對其他並發事務是隔離的,並發執行的各個事務之間不能互相干擾。 4.
持久性:一個事務一旦提交,它對資料庫中資料的改變就應該是永久性的。接下來的其他動作或故障不應該對其執行結果有任何影響。 結合前面的例子解釋一下概念:在轉賬樣本中A扣100元錢和B加100元錢這兩步更新操作就是一個操作序列。這兩步是一個整體要麼全部成功,要麼全部成功,絕對不能只成功一步而另一步失敗。關於資料庫事務的詳細知識請參考有關的資料庫原理書籍。 Spring架構令人信服的重要因素之一是它全面的事務支援。Spring支援“編程式事務”和“聲明式事務”
二、在
Spring
中編寫事務 在我們的代碼中添加事務的一種方法就是使用Spring的TransactionTemplate類,用程式添加事務邊界。就像其他Spring的模版類一樣,TransactionTemplate利用一套回調機制,把我們的程式碼封裝裝在一個TransactionTemplate裡。看下面的代碼片斷:
public
void enrollStudentInCourse() { tran.execute(
new TransactionCallback() {
public Object doInTransaction(TransactionStatus ts){
try{ //do something.... }
catch(Exception ex){ ts.setRollbackOnly();//出錯進行交易回復 }
return
null; } } ); } 下面是設定檔: <bean id = "transactionTemplate" class = "org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager"><ref bean = "transactionTemplate"/></property> </bean> <bean id = "courseService" class = "MyImp"> <property name="transactionTemplate"><ref bean = "transactionTemplate"/></property> </bean> transactionTemplate對象有一個transactionManager屬性。該屬性為PlatformTransactionManager類型,它用來處理特定平台的交易管理的細節。也可以直接使用 org.springframework.transaction.PlatformTransactionManager的實現來管理事務。只需通過bean引用簡單地傳入一個 PlatformTransactionManager實現,然後使用 TransactionDefinition和 TransactionStatus對象,你就可以啟動一個事務,提交或復原。在上例的簡單代碼中我們展示的是“編程式事務”當你完全希望控制事務的邊界時候,“編程式事務”是不錯的。但是他有些侵入性。通常我們的事務需求並沒有要求在事務的邊界上進行如此精確的控制。我們可以使用“聲明式事務”。
三、聲明式事務 大多數Spring使用者選擇聲明式交易管理。這是對應用代碼影響最小的選擇,因此也最符合非侵入式輕量級容器的理念。Spring的聲明式交易管理是通過Spring AOP實現的,因為事務方面的代碼與Spring綁定並以一種樣板式風格使用,這樣做是非常自然的,因為事務時系統級的,淩駕於應用的主要功能之上的,你可以把Spring的事務想象成是一個切面(方面)包裹著一個方法。不過儘管如此,你一般並不需要理解AOP概念就可以有效地使用Spirng的聲明式交易管理。 在 Spring2.0 之前要在 Spring 中使用聲明式事務,得用 TransactionProxyFactoryBean 。這是一個介面,他有點類似在第三章中的 ProxyFactoryBean ,只不過它的目的是將方法封裝在事務的上下文中。 Spring2.0 及以後的版本中聲明式事務的配置與之前的版本有相當大的不同。主要差異在於不再需要配置 TransactionProxyFactoryBean 了。 Spring2.0 之前的舊版本風格的配置仍然是有效;你可以簡單地認為新的 <tx:tags/> 替你定義了 TransactionProxyFactoryBean 。和 TransactionProxyFactoryBean 配合的還有兩個,一個是 PlatformTransactionManager 另一個是 TransactionAttributeSource 。
1
.理解事務屬性: 在Spring裡,事務屬性是對事務策略如何應用到方法的描述。這個描述包括下列一些參數:傳播行為、隔離等級、唯讀提示、事務逾時間隔。 (1)傳播行為 傳播行為定義了關於用戶端和被呼叫者法的事務邊界。Spring定義了7種截然不同的傳播行為。(在書中165頁有詳細列表)Spring的傳播行為分別對應了EJB容器管理的事務(CMT)中所有的傳播規則。傳播規則回答了一個問題,就是新的事務是否要被啟動或是被掛起,或者方法是否要在事務環境中運行。 (2)隔離等級 在一個典型的應用中,多個事務並發運行,經常會操作同一個資料來完成任務。並發會導致以下問題: l 髒讀——髒讀發生在一個事務讀取了被另一個事務改寫但還未提交的資料時。 l 不可重複讀取——不可重複讀取發生在一個事務執行相同的查詢兩次或兩次以上,但每一次查詢結果不同時。 l 幻讀——幻讀和不可重複讀取相似。 在理想狀態下,事務要完全相互隔離,以防止這些問題發生。(這些內容在資料庫原理裡面都有講解,大家可以參考資料庫原理的相關書)然而完全隔離會影響效能,因為隔離經常牽扯到鎖定在資料庫中的記錄。侵佔性的鎖定會阻礙並發,要求事務相互等待來完成工作,這樣會引起“事務死結”。 應該認識到完全隔離會影響效能,並且不是所有應用都需要完全隔離,有時候應用需要在事務隔離上有些彈性。因此也有好幾個隔離等級,見書166頁下面的表格。 (3)唯讀 如果一個事務只對後段資料庫執行讀操作,資料庫就可能利用事務唯讀特性,使用某些最佳化措施。通過聲明一個事務為唯讀,你就給了後端資料庫一個機會,來應用那些它認為合適的最佳化措施。 (4)事務逾時 在事務中你可能選擇設定的另一個屬性就是逾時。假設你的事務在預料之外長時間運行,因為事務可能涉及對後端資料庫的鎖定,長時間啟動並執行事務會不必要的佔用資料庫資源。與其等他結束,不如聲明一個事務,在特定秒數後自動復原。
四、通過方法名聲明事務 NameMatchTransactionAttributeSource,這個事務屬性源讓你在方法名的基礎上聲明事務屬性。看下面的例子: <bean id = "transactionAttuibuteSource" class = "org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource"> <property name="properties"> <props> <prop key="enrollStudentInCourse"> PROPAGATION_REQUIRES_NEW </prop> </props> </property> </bean> 被命名為transactionAttuibuteSource的bean 將被置入到TransactionProxyFactoryBean的transactionAttuibuteSource屬性中。 NameMatchTransactionAttributeSource的properties屬性把方法名映射到事務屬性描述器上。事務屬性描述器有以下幾種形式: l PROPAGATION——傳播行為 l ISOLATION——隔離等級(可選) l Readonly——是唯讀事務嗎。(可選) l -Exeptions——復原規則(可選) l +Exception——同上 在上面的例子中,只指定了傳播行為。但是,事務的許多其他參數都可以在事務屬性描述器中定義。
指定交易隔離等級 <bean id = "transactionAttuibuteSource" class = "org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource"> <property name="properties"> <props> <prop key="enrollStudentInCourse"> PROPAGATION_REQUIRES_NEW, ISOLATION_REPEATABLE_READ </prop> </props> </property> </bean>
使用唯讀事務 <bean id = "transactionAttuibuteSource" class = "org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource"> <property name="properties"> <props> <prop key="enrollStudentInCourse"> PROPAGATION_REQUIRES_NEW, ISOLATION_REPEATABLE_READ, readOnly </prop> </props> </property> </bean>
指定復原規則