1. 程式人生 > 其它 >Spring宣告式事務控制

Spring宣告式事務控制

Spring宣告式事務控制

什麼是事務控制?

與資料庫建立連線connection後,每一次的進行查詢、更新操作,如果沒有將其歸為一個事務,則是獨立進行的。

而這樣會導致一些錯誤場景的發生。(經典的如銀行轉賬業務,轉出方錢減少了,期間發生了異常,對方的錢卻沒有到賬等情況)

為什麼要先了解程式設計式事務?

宣告式事務底層即通過程式設計式事務進行控制。而其中有部分引數、資訊需要了解,再在XML中進行配置。

故而需要了解程式設計式事務的相關物件、定義資訊。

程式設計式事務控制相關物件

PlatformTransactionManager

PlatformTransactionManager介面是 spring的事務管理器,它裡面提供了我們常用的操作事務的方法。

注意:

PlatformTransactionManager是介面型別,不同的Dao層技術則有不同的實現類,例如:

Dao層技術是jdbc或mybatis時:org.springframework.jdbc.datasource.DataSourceTransactionManager

Dao層技術是hibernate時:org.springframework.orm.hibernate5.HibernateTransactionManager

TransactionDefinition

TransactionDefinition 是事務的定義資訊物件,裡面有如下方法:

該類中相關的概念:

1.事務隔離級別(Isolation)

設定隔離級別,可以解決事務併發產生的問題,如髒讀、不可重複讀和虛讀。

  • ISOLATION_DEFAULT
  • ISOLATION_READ_UNCOMMITTED
  • ISOLATION_READ_COMMITTED
  • ISOLATION_REPEATABLE_READ
  • ISOLATION_SERIALIZABLE

2.事務傳播行為(Propogation)

  • REQUIRED:如果當前沒有事務,就新建一個事務,如果已經存在一個事務中,加入到這個事務中。一般的選擇(預設值)
  • SUPPORTS:支援當前事務,如果當前沒有事務,就以非事務方式執行(沒有事務)
  • MANDATORY:使用當前的事務,如果當前沒有事務,就丟擲異常
  • REQUERS_NEW:新建事務,如果當前在事務中,把當前事務掛起。
  • NOT_SUPPORTED:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起
  • NEVER:以非事務方式執行,如果當前存在事務,丟擲異常
  • NESTED:如果當前存在事務,則在巢狀事務內執行。如果當前沒有事務,則執行 REQUIRED 類似的操作
  • 超時時間:預設值是-1,沒有超時限制。如果有,以秒為單位進行設定
  • 是否只讀:建議查詢時設定為只讀

TransactionStatus

TransactionStatus 介面提供的是事務具體的執行狀態,方法介紹如下。

程式設計式事務控制知識要點

程式設計式事務控制三大物件

  • PlatformTransactionManager
  • TransactionDefinition
  • TransactionStatus

基於XML的宣告式事務控制

什麼是宣告式事務控制?

Spring 的宣告式事務顧名思義就是採用宣告的方式來處理事務。這裡所說的宣告,就是指在配置檔案中宣告 ,用在 Spring 配置檔案中宣告式的處理事務來代替程式碼式的處理事務。

宣告式事務處理的作用

  • 事務管理不侵入開發的元件。具體來說,業務邏輯物件就不會意識到正在事務管理之中,事實上也應該如此,因為事務管理是屬於系統層面的服務,而不是業務邏輯的一部分,如果想要改變事務管理策劃的話, 也只需要在定義檔案中重新配置即可
  • 在不需要事務管理的時候,只要在設定檔案上修改一下,即可移去事務管理服務,無需改變程式碼重新編譯 ,這樣維護起來極其方便

注意:Spring宣告式事務控制底層就是AOP實現的。

宣告式事務控制的實現

宣告式事務控制明確事項:

  • 誰是切點?
  • 誰是通知?
  • 配置切面?

由其是AOP實現的。故而可以想到:

  • 切點就是需要進行事務控制的業務邏輯方法。
  • 通知即advisor,是宣告式控制事務底層的程式設計式事務控制的相關類方法。(由spring根據不同的dao層技術進行具體實現的類方法,用於進行事務控制)
  • 配置切面即在XML中進行aop:config等的配置,自定義的切面用aspect,而宣告式事務控制用advisor

快速實現

1.引入tx名稱空間

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

2.配置事務增強

<!--平臺事務管理器-->
<bean id="transactionManager"  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"></property>
</bean>

<!--事務增強配置-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
    	<tx:method name="*"/>
    </tx:attributes>
</tx:advice>

3.配置事務AOP織入

<!--事務的aop增強-->
<aop:config>
	<aop:pointcut id="myPointcut" expression="execution(* com.itheima.service.impl.*.*(..))"/>
	<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"></aop:advisor>
</aop:config>

4.測試事務控制轉賬業務程式碼

@Override
public void transfer(String outMan, String inMan, double money) {
    accountDao.out(outMan,money);
    int i = 1/0;
    accountDao.in(inMan,money);
}

之後可以看到,由其轉出轉入在同一個事務控制之下。即transfer方法下的操作屬於同一事務,在異常發生時,沒有進行事務提交,故而不會出現業務問題。

切點方法的事務引數的配置

<!--事務增強配置-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
    	<tx:method name="*"/>
    </tx:attributes>
</tx:advice>

其中,《tx:method》 代表切點方法的事務引數的配置,例如:

<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" 
read-only="false"/>
  • name:切點方法名稱
  • isolation:事務的隔離級別
  • propogation:事務的傳播行為
  • timeout:超時時間
  • read-only:是否只讀

基於XML的宣告式事務控制知識要點

  • 平臺事務管理器配置
  • 事務通知的配置
  • 事務aop織入的配置

基於註解的宣告式事務控制

這裡使用註解進行宣告式事務控制。

快速實現

1.編寫AccountDao

@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    public void out(String outMan, double money) {
    	jdbcTemplate.update("update account set money=money-? where name=?",money,outMan);
    }
    
    public void in(String inMan, double money) {
    jdbcTemplate.update("update account set money=money+? where name=?",money,inMan);
    }
}

2.編寫AccountService

@Service("accountService")
@Transactional
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);
    }
}

3.編寫applicationContext.xml配置檔案

<!—之前省略datsSource、jdbcTemplate、平臺事務管理器的配置-->
<!--元件掃描-->
<context:component-scan base-package="com.itheima"/>
<!--事務的註解驅動-->
<tx:annotation-driven/>

註解的相關配置詳解

  1. 使用 @Transactional 在需要進行事務控制的類或是方法上修飾,註解可用的屬性同 xml 配置方式,例如隔離 級別、傳播行為等。
  2. 註解使用在類上,那麼該類下的所有方法都使用同一套註解引數配置。
  3. 使用在方法上,不同的方法可以採用不同的事務引數配置。
  4. XML配置檔案中要開啟事務的註解驅動

基於註解的宣告式事務控制知識要點

  • 平臺事務管理器配置(xml方式)
  • 事務通知的配置(@Transactional註解配置)
  • 事務註解驅動的配置 《tx:annotation-drive/》