學習筆記--Spring的事務控制
1.程式設計式事務控制相關物件
1.1 PlatformTransactionManager
該介面是Spring的事務管理器,它裡面提供了我們常用的操作事務的方法。
不同的技術,使用了不同的實現類實現該介面。
1.2 TransactionDefinition
是事務的定義資訊物件。裡面包含著事務的相關資訊。裡面有如下方法
方法 | 說明 |
int getIsolationLevel() | 獲得事務的隔離級別 |
int getPropogationBehavior() | 獲得事務的傳播行為 |
int getTimeout() | 獲得超時時間 |
boolean isReadOnly() | 是否只讀 |
1.事務隔離級別:設定隔離級別,可以解決事務併發產生的問題,如髒讀、不可重複讀和虛讀。
2.事務傳播行為。
REQUIRED:如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中,一般的選擇。
SUPPORTS:支援當前事務,如果當前沒有事務,就以非事務方式執行(沒有事務)。
1.3 TransactionStatus
該介面的是事務具體的執行狀態。
方法 | 說明 |
boolean hasSavePoint() | 是否儲存回滾點 |
boolean isCompleted() |
事務是否完成 |
boolean isNewTransaction() |
是否是新事務 |
boolean isRollbackOnly() | 事務是否滾回 |
被動封裝事務狀態資訊。
2.基於XML的宣告式事務控制
2.1 什麼是宣告式事務控制
採用宣告的方式處理事務,這裡說的宣告,就是在配置檔案中宣告,在Spring配置檔案中宣告式的處理事務來代替程式碼式的處理事務。
作用:
事務管理不侵入開發的元件,因為事務管理是屬於系統層面的服務,不是業務邏輯的一部分。
業務邏輯物件不會意識到正在事務管理之中。
(AOP的思想)
在不需要事務管理的時候,只需要在設定檔案上修改一下,即可移除事務管理服務,無需改變程式碼。
注意:Srping宣告式事務控制底層就是AOP
AOP的延展
2.2 宣告式事務控制的實現
我們想對Service層下的transfer方法進行事務控制,目的是為了將轉出和轉入的操作作為一個事務整體,同成功同失敗。
避免出現一方轉出成功,一方轉入失敗仍然進行的問題。
public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public void transfer(String outMan, String inMan, double money) { //開啟事務 accountDao.out(outMan,money); int i = 1/0; accountDao.in(inMan,money); //提交事務 } }
我們對transfer中間進行自發的一個異常錯誤,我們需要做的是在執行轉出方法前開啟事務,在轉入方法執行結束後結束事務,以達到統一的一個目的。
要達到Spring的事務控制,我們需要對xml進行控制。
<!-- 配置一個平臺事務管理器 不同的技術實現用不同的事務管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 通知:事務的增強--> <tx:advice id="txAdive" transaction-manager="transactionManager"> <!-- 設定事務的屬性資訊 --> <tx:attributes> <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" timeout="-1"/> <tx:method name="*" /> </tx:attributes> </tx:advice> <!-- 配置事務AOP的織入 --> <aop:config> <aop:advisor advice-ref="txAdive" pointcut="execution(* com.itheima.service.impl.*.*(..))"/> </aop:config>
第一個要配置的是平臺事務管理器,不同的計算對應著不同的事務管理器類,所以要注意區分,裡面需要注入DataSource屬性,因為Spring通過資料庫連線來控制事務。
第二個要配置的是事務的增強方法(與AOP不同的是不用自己定義增強類),由於用到了tx名稱空間,所以使用前要引入tx的名稱空間。這裡配置了用的平臺事務管理器,還有對不同方法的不同事務引數配置。
第三個要配置的是事務AOP的織入,與AOP一樣,pointcut裡面寫的是對什麼範圍的業務方法使用業務增強。
2.3 切點方法的事務引數配置
<!-- 通知:事務的增強--> <tx:advice id="txAdive" transaction-manager="transactionManager"> <!-- 設定事務的屬性資訊 --> <tx:attributes> <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" timeout="-1"/> <tx:method name="*" /> </tx:attributes> </tx:advice>
name:切點方法名稱
isolation:事務的隔離級別
propagation:事務的傳播行為
timeout:超時時間
read-only:是否只讀
3.基於註解的宣告式事務控制
3.1 快速實現
主要是將以下配置改成註解方式。
<!-- 通知:事務的增強--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 設定事務的屬性資訊 --> <tx:attributes> <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" timeout="-1"/> <tx:method name="*" /> </tx:attributes> </tx:advice> <!-- 配置事務AOP的織入 --> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.service.impl.*.*(..))"/> </aop:config>
這些全部在業務方法類上進行,也就是Service層。
@Service("accountService") @Transactional(isolation = Isolation.READ_COMMITTED) public class AccountServiceImpl implements AccountService { @Autowired private AccountDao accountDao; @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED) public void transfer(String outMan, String inMan, double money) { //開啟事務 accountDao.out(outMan,money); int i = 1/0; accountDao.in(inMan,money); //提交事務 } // @Transactional() public void xxx(){} }
使用@Transactional註解來完成,註解可用的屬性同xml配置方式。
如果該註解出現在整個Service類上,表明該類的所有業務方法都採用該註解所對應的值來配置。
如果該註解出現在某個業務方法上,表明該業務方法的某個配置。
如果都有,服從就近原則。
xml配置檔案要開啟事件的註解驅動
<tx:annotation-driven transaction-manager="transactionManager"/>