歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Spring編程式事務管理

Spring編程式事務管理

日期:2017/3/1 9:12:49   编辑:Linux編程

在基於數據庫的應用中,事務是非常重要的。為了方便使用,Spring提供了基於XML和基於注解的方式配置事務,思路都是使用AOP,在特定的切入點統一開啟事務,以方法為粒度進行事務控制。並且定義了事務的傳播屬性,規定了配置了事務的方法互相嵌套調用時的行為准則:

  • PROPAGATION_REQUIRED:支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
  • PROPAGATION_SUPPORTS:支持當前事務,如果當前沒有事務,就以非事務方式執行。
  • PROPAGATION_MANDATORY:支持當前事務,如果當前沒有事務,就拋出異常。
  • PROPAGATION_REQUIRES_NEW:新建事務,如果當前存在事務,把當前事務掛起。
  • PROPAGATION_NOT_SUPPORTED:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
  • PROPAGATION_NEVER:以非事務方式執行,如果當前存在事務,則拋出異常。
  • PROPAGATION_NESTED:支持當前事務,新增Savepoint點,與當前事務同步提交或回滾。

越是統一的東西,靈活性就越差。事務是業務邏輯的一部分,有時候事務的開啟並不能以方法為粒度進行統一控制,這時候很多開發人員的做法是"將就"基於AOP的事務配置的方法,將需要開啟事務的邏輯單獨拆出方法進行控制,這其實是一種妥協,而且有時候並不見得稱心如意。那麼Spring除了基於AOP,還有別的方式管理事務嗎?答案就是org.springframework.transaction.support.TransactionTemplate。下面我們研究下它的使用。首先看下類圖:

TransactionTemplate繼承了DefaultTransactionDefinition,它是TransactionDefinition的一個實現,TransactionDefinition是Spring事務管理中很重要的一個概念,它是事務配置的入口,可以配置事務的各種屬性,如隔離級別、傳播屬性、超時時間、是否只讀,通過實現這個接口,TransactionTemplate具備了配置事務的能力。另外必須為它指定transactionManager,畢竟它只是負責觸發事務的開啟,並不具備事務管理的能力:

    <bean id="sessionFactory"
          class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="packagesToScan">
            <list>
                <!-- 可以加多個包 -->
                <value>com.cuilei01.mgr.utils</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>

                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
            </props>
        </property>
    </bean>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName">
            <value>com.mysql.jdbc.Driver</value>
        </property>
        <property name="url">
            <value>${jdbc.mgr.url}</value>
        </property>
        <property name="username">
            <value>${jdbc.mgr.user}</value>
        </property>
        <property name="password">
            <value>${jdbc.mgr.password}</value>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"></property>
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置transactionTemplate -->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"></property>
        <!--定義事務隔離級別,-1表示使用數據庫默認級別-->
        <property name="readOnly" value="false"></property>
        <property name="isolationLevelName" value="ISOLATION_DEFAULT"></property>
        <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"></property>
    </bean>

現在就可以在Spring管理的Bean中注入並使用:

@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class TransactionTest {

    private final Logger logger = LoggerFactory.getLogger(TransactionTest.class);

    @Resource
    private TransactionTemplate transactionTemplate;

    @Test
    public void testProgrammaticTransaction() {
        logger.info("Begin test programmatic transaction!########################");
        // 第一個事務
        Integer result = transactionTemplate.execute(new TransactionCallback<Integer>() {
            @Override
            public Integer doInTransaction(TransactionStatus status) {
                logger.info("Do in transaction with a return value!#####################################");
                // 在事務中執行, 有返回值
                return 1;
            }
        });

        logger.info("result:{}", result);

        // 第二個事務
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                logger.info("Do in transaction without a return value!#####################################");
                // 在事務中執行,沒有返回值
            }
        });
    }

看到TransactionTemplate的使用比較簡單,只需將需要在事務中之行的邏輯封裝成TransactionCallback<T>,這個是帶返回值的,不帶返回值的封裝成TransactionCallbackWithoutResult。

觀察下事務的執行情況,事務work了。

看下它的核心代碼:

@Override
	public <T> T execute(TransactionCallback<T> action) throws TransactionException {
		if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
			return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
		}
		else {
			TransactionStatus status = this.transactionManager.getTransaction(this);
			T result;
			try {
				result = action.doInTransaction(status);
			}
			catch (RuntimeException ex) {
				// Transactional code threw application exception -> rollback
				rollbackOnException(status, ex);
				throw ex;
			}
			catch (Error err) {
				// Transactional code threw error -> rollback
				rollbackOnException(status, err);
				throw err;
			}
			catch (Exception ex) {
				// Transactional code threw unexpected exception -> rollback
				rollbackOnException(status, ex);
				throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
			}
			this.transactionManager.commit(status);
			return result;
		}
	}


需要執行事務的業務邏輯被封裝成action,它所做的也很簡單,在action執行前後進行事務的開啟和提交(或著rollback)。開啟事務時需要transactionManager的getTransaction方法獲取TransactionStatus,而這個方法的參數是TransactionDefinition,前面說過TransactionTemplate本身就是TransactionDefinition的實現,所以將this作為參數傳遞給這個方法就可以。

也可以看到,TransactionTemplate和基於AOP的配置一樣,也是在方法前後執行事務的開啟和提交,只是實現的方式改變了。

Spring中如何配置Hibernate事務 http://www.linuxidc.com/Linux/2013-12/93681.htm

Struts2整合Spring方法及原理 http://www.linuxidc.com/Linux/2013-12/93692.htm

基於 Spring 設計並實現 RESTful Web Services http://www.linuxidc.com/Linux/2013-10/91974.htm

Spring-3.2.4 + Quartz-2.2.0集成實例 http://www.linuxidc.com/Linux/2013-10/91524.htm

使用 Spring 進行單元測試 http://www.linuxidc.com/Linux/2013-09/89913.htm

運用Spring注解實現Netty服務器端UDP應用程序 http://www.linuxidc.com/Linux/2013-09/89780.htm

Spring 3.x 企業應用開發實戰 PDF完整高清掃描版+源代碼 http://www.linuxidc.com/Linux/2013-10/91357.htm

Spring 的詳細介紹:請點這裡
Spring 的下載地址:請點這裡

Copyright © Linux教程網 All Rights Reserved