天天看點

spring筆記--事務管理之聲明式事務

  • 事務簡介:

    事務管理是企業級應用開發中必不可少的技術,主要用來確定資料的完整性和一緻性,

    事務:就是一系列動作,它們被當作一個獨立的工作單元,這些動作要麼全部完成,要麼全部不起作用.

  • Spring中使用事務:

    作為一個受歡迎的企業應用架構,Spring在不同的事務管理API上定義了一個抽象層,而開發時不必了解底層的事務管理API,就可以使用Spring的事務管理機制.

    Spring既支援程式設計式的事務管理,也支援聲明式的事務管理,大多數情況我們選擇後者.

      程式設計式事務管理:将事務管理代碼嵌入到業務代碼中來控制事務的送出和復原,在程式設計式事務管理中,必須在每一個事務操作中包含額外的事務管理代碼.

      聲明式事務管理:将事務管理代碼從業務方法中分離出來,以聲明的方式來實作事務管理,事務管理作為一種橫切關注點,可以通過AOP的方式子產品化. 

    下面介紹一下在Spring中使用注解方式開啟聲明式事務的配置檔案代碼(beans.xml):

<?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:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        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-4.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
     <!-- 導入資源檔案 -->
     <context:property-placeholder location="db.properties"
         ignore-resource-not-found="false" />
     <!-- 配置c3p0連接配接池 -->
     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
     <property name="initialPoolSize" value="${jdbc.initialPoolSize}"></property>
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
    </bean>
    <!-- 配置jdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
    
    </bean>
    <!--步驟一: 配置事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 步驟二:啟用事務注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>      

    步驟三: 配置完成以後,在需要開始事務的方法添加@Transactional注解,即可在該方法中開啟并使用事務.

  • 事務的傳播屬性:

    當事務方法被另一個事務方法調用時,必須指定事務應該如何傳播,例如:方法可以繼續在現有事務中運作,也可以開啟一個新的事務,在新的事務中執行.

    在@Transactional中,有一個參數叫propagation,用于指定事物的傳播行為,預設值為REQUIRED,即使用調用方法的事務.

      @Transactional(propagation=Propagation.REQUIRED):不開啟新的事務

      @Transactional(propagation=Propagation.REQUIRED_NEW):開啟新的事務

    那麼應該如何了解呢,假設我現在有100塊錢,我需要買兩本書,A和B,A賣60塊錢,庫存還有10本,B賣50塊錢,庫存也有十本,在方法buyBook()中,需要同時調用方法BuyBookA(),和buyBookB();

    如果選擇REQUIRED的話,結果是一本也買不了,因為在買完A後,我隻剩40塊錢,在買B的時候,因為錢不夠,是以購買失敗,事務復原到buyBook方法最初的位置(buyBookA方法之前),即A,B都沒有買成.

    如果選擇的是REQUIRED_NEW的話,那麼會成功購買A,而無法購買B,因為在buyBook方法中,當調用buyBookA()時,會開啟一個新事務,在購買成功時,事務送出,資料庫更新,這時候我隻剩40塊錢,再調用buyBookB()時自然會因為錢不夠而事務復原.最後的結果就是,A購買成功,B購買失敗.

  • 事務的其他屬性:

    使用isolation指定事務的隔離級别,最常用的取值為READ_COMMITTED

    使用readOnly指定事物是否為隻讀,表示這個事務隻讀取資料而不更新資料,這樣可以幫助資料庫引擎優化事務,

    使用timeOut指定事務復原之前可以占用的時間.

  @Transactional(isolation=Isolation.READ_COMMITTED,readOnly=true,timeout=5)      

以上都是使用注解的方式啟用聲明式事務,下面介紹一下使用xml檔案配置事務的方式:

  beans.xml(配置bean的過程省略):

<?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:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        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-4.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
     <!-- 導入資源檔案 -->
     <context:property-placeholder location="db.properties"
         ignore-resource-not-found="false" />
     <!-- 配置c3p0連接配接池 -->
     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
     <property name="initialPoolSize" value="${jdbc.initialPoolSize}"></property>
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
    </bean>
    <!-- 配置jdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
    
    </bean>
    <!--步驟1: 配置事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
    <!-- 步驟2:配置事務屬性 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
     <!--根據方法名指定事物的屬性-->

            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
    
    <!-- 步驟3:配置事物切入點,把事物切入點和事務屬性關聯起來 -->
    <aop:config>
        <aop:pointcut expression="execution(* com.wang.dao.UserDao.*(..))" id="pointcut"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>
    
</beans>