(筆記)Spring實戰_事務管理(4)_聲明式事務

Spring對聲明式事務的支持是通過使用Spring AOP框架實現的。自從Spring2.0,聲明事務的更好方式是使用Spring的tx命名空間和@Transactional註解。
1.定義事務屬性
事務屬性描述了事務策略如何應用到方法上。事務屬性包含了5個方面:
傳播行爲
傳播行爲定義了客戶端與被調用方法之間的事務邊界。

傳播行爲 含義
PROPAGATION_MANDATORY 表示該方法必須在事務運行,如果當前事務不存在,則會拋出一個異常
PROPAGATION_NESTED 表示如果當前已經存在一個事務,那麼該方法將會在嵌套事務中運行。嵌套的事務可以獨立於當前事務進行單獨地提交或回滾。如果當前事務不存在,那麼其行爲與PROPAGATION_REQUIRED一樣。注意各個廠商對這種傳播行爲的支持是有所差異的。可以參考資源管理器的文檔來確定它們是否支持嵌套式事務
PROPAGATION_NEVER 表示當前方法不應該運行在事務上下文中。如果當前正有一個事務在運行,則會拋出異常
PROPAGATION_NOT_SUPPORTED 表示該方法不應該運行在事務中。如果存在當前事務,在該方法運行期間,當前事務將被掛起
PROPAGATION_REQUIRED 表示當前方法必須運行在事務中。如果當前事務存在,方法將會在該事務中運行。否則,會啓動一個新的事務
PROPAGATION_REQUIRES_NEW 表示當前方法必須運行在它自己的事務中。一個新的事務將被啓動。如果存在當前事務,在該方法執行期間,當前事務會被掛起

上述描述的傳播行爲都在org.springframework.transaction.TransactionDefinition接口中以常量的方式進行了定義。

傳播規則回答了這樣一個問題,即新的事務應該被啓動還是被掛起,或者方法是否要在事務環境中運行。
隔離級別
隔離級別定義了一個事務可能受其他併發事務影響的程度。
在典型地應用程序中,多個事務併發運行,經常會操作相同的數據來完成各自的任務。併發可能會導致以下問題:
髒讀:髒讀發生在一個事務讀取了另一個事務改寫但尚未提交的數據時。如果改寫在稍後被回滾了,那麼第一個事務獲取的數據就是無效的。
不可重複讀:不可重複讀發生在一個事務執行相同的查詢兩次或兩次以上,但是每次都得到不同的數據時。這通常是因爲另一個併發事務在兩次查詢期間更新了數據。
幻讀:幻讀與不可重複讀類似。它發生在一個事務讀取了幾行數據,接着另一個併發事務插入了一些數據時。在隨後的查詢中,第一個事務就會發現多了一些原本不存在的記錄。
在理想情況下,事務之間是完全隔離的,從而可以防止這些問題發生。但是完全的隔離會導致性能問題,因爲它通常會涉及鎖定數據庫中的記錄(有時候甚至是整張表)。侵佔性的鎖定會阻礙併發性,要求事務相互等待以完成各自的工作。

隔離級別 含義
ISOLATION_DEFAULT 使用後端數據庫默認的隔離級別
ISOLATION_READ_UNCOMMITTED 允許讀取尚未提交的數據變更。可能會導致髒讀、幻讀或不可重複讀
ISOLATION_READ_COMMITTED 允許讀取併發事務已經提交的數據。可以阻止髒讀,但是幻讀或不可重複讀仍有可能發生
ISOLATION_REPEATABLE_READ 對同一字段的多次讀取結果是一致的,除非數據是被本事務自己所修改。可以阻止髒讀和不可重複讀,但幻讀仍有可能發生
ISOLATION_SERIALIZABLE 完全服從ACID的隔離級別,確保阻止髒讀、不可重複讀以及幻讀。這是最慢的事務隔離級別,因爲它通常是通過完全鎖定事務相關的數據庫來實現的

上述描述的隔離級別都在org.springframework.transaction.TransactionDefinition接口中以常量的方式進行了定義。

只讀
如果事務只對後端的數據庫進行讀操作,數據庫可以利用事務的只讀特性來進行一些特定的優化。通過將事務設置爲只讀,你就可以給數據庫一個機會,讓它應用它認爲合適的優化措施。
因爲只讀優化是在事務啓動的時候由數據庫實施的,只有對那些具備啓動一個新事務的傳播行爲(PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW以及PROPAGATION_NESTED)的方法來說,將事務聲明爲只讀纔是有意義的。
另外,如果採用Hibernate作爲持久化機制,那麼將事務聲明爲只讀會導致Hibernate的flush模式被設置爲FLUSH_NEVER。這會告訴Hibernate避免和數據庫進行不必要的對象同步,並將所有的更新延遲到事務結束。
事務超時
因爲事務可能涉及對後端數據庫的鎖定,所有長時間的事務會不必要地佔用數據庫資源。你可以聲明一個事務,在特定的秒數後自動回滾,而不是等待其結束。
因爲超時時鐘會在事務開始時啓動,所有,只有對那些具備可能啓動一個新事務的傳播行爲(PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW以及PROPAGATION_NESTED)的方法來說,聲明事務超時纔有意義。
回滾規則
定義了哪些異常會導致事務回滾而哪些不會。默認情況下,事務只有在遇到運行期異常時纔會回滾,而在遇到檢查型異常時不會回滾。
但是你可以聲明事務在遇到特定的檢查型異常時像遇到運行期異常那樣回滾。同樣,你還可以聲明事務遇到特定的異常不回滾,即使這些異常是運行期異常。
2.在XML中定義事務
tx命名空間和aop命名空間

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
  http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/tx
  http://www.springframework.org/schema/tx/spring-tx.xsd
  http://www.springframework.org/schema/aop
  http://www.springframework.org/schema/aop/spring-aop.xsd">

<tx:advice>聲明事務性策略

    <tx:advice id="txAdvice">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="*" propagation="SUPPORTS" read-only="true" />
        </tx:attributes>
    </tx:advice>

<tx:method>元素爲某個(或某些)name屬性(使用通配符)指定的方法定義事務參數。

隔離級別 含義
isolation 指定事務的隔離級別
propagation 定義事務的傳播規則
read-only 指定事務爲只讀
回滾規則:rollback-for no-rollback-for rollback-for指定事務對於哪些檢查型異常應該回滾而不提交;no-rollback-for指定事務對於哪些異常應當繼續運行而不回滾
timeout 對於長時間運行的事務定義超時時間

當使用<tx:advice>來聲明事務時,你還需要一個事務管理器。根據約定優於配置,<tx:advice>假定事務管理器被聲明爲一個id爲transactionManager的Bean。如果碰巧爲事務管理器配置了一個不同的id,則需要在transaction-manager屬性中明確指明事務管理器的id。

    <tx:advice id="txAdvice" transaction-manager="txManager">
        ...
    </tx:advice>

<tx:advice>只是定義了AOP通知,用於把事務邊界通知給方法。但是這只是事務通知,而不是完整的事務性切面。我們在<tx:advice>中沒有聲明哪些Bean應該被通知——我們需要一個切點來做這件事。爲了完整定義事務性切面,我們必須定義一個通知器(advisor)。這就涉及aop命名空間了。

    <aop:config>
        <aop:advisor pointcut="execution(* *..SpitterService.*(..))"
            advice-ref="txAdvice" />
    </aop:config>

3.定義註解驅動的事務

<tx:annotation-driven transaction-manager="txManager" />

<tx:annotation-driven>元素告訴Spring檢查上下文中所有的Bean並查找使用@Transactional註解的Bean,而不管這個註解是用在類級別還是方法級別上。對於每一個使用@Transactional註解的Bean,<tx:annotation-driven>會自動爲它添加事務通知。通知的事務屬性是通過@Transactional註解的參數來定義的。

@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章