1. 程式人生 > >Spring怎麼實現控制事務

Spring怎麼實現控制事務

轉自:https://www.cnblogs.com/teach/p/5823574.html
在開發中需要操作資料庫,進行增、刪、改操作的過程中屬於一次操作,如果在一個業務中需要更新多張表,那麼任意一張表的更新失敗,整個業務的更新就是失敗,這時那些更新成功的表必須回滾,否則業務會出錯,這時就要用到事務,即這個業務的操作屬於一個事務,事務具有原子性、隔離性、一致性、持續性。這時便用到了事務,事務控制的目的是保證一組操作要麼全部成功,要麼全部失敗。spring提供了對事務的支援,在spring中主要有兩種方式使用事務,一、程式設計式事務控制;二、宣告式事務控制。

一、程式設計式事務控制

所謂程式設計式事務控制即通過編寫程式碼的方式實現事務的控制。

spring為了方便處理事務,提供了事務管理器,對事務的控制歸根到底是通過事務管理器進行控制,在spring中所有的事務控制必須要有事務管理器。下面是一個程式設計式事務控制的例子,實現賬戶之間的轉賬,我們把對事務的控制放在系統的service層(分為controller層、service層、DAO層)來處理,下面是我的spring配置檔案,

<?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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!--spring 自動檢測-->
 
<context:component-scan base-package="com.cn.study.day5" />
<!---->
<context:property-placeholder location="classpath:db.properties"/>
<!---->

 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName">
        <value>${db.driver}</value>
    </property>
    <property name="url">
        <value>${db.url}</value>
    </property>
    <property name="username">
        <value>${db.username}</value>
    </property>
    <property name="password">
        <value>123456</value>
    </property>
</bean>  
 
    <bean id="dao" class="com.cn.study.day5.service.inter.impl.AccountDaoImpl">
     
    <property name="dataSource" ref="dataSource"></property>
</bean>
 
<!--配置事務管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
     
</bean>
<!--事務管理器模板 方便使用事務-->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
    <property name="transactionManager" ref="transactionManager"></property>
</bean>
  配置了事務管理器,這裡使用DataSourceTransactionManager,事務管理器有一個dataSource屬性必須配置,這裡使用ref屬性引用上邊的。有了事務管理器之後要使用事務還是比較麻煩,spring又提供了事務管理器模板,我們配置事務管理器模板,事務管理器模板需要一個事務管理器屬性,我們引用上邊的事務管理器。至此關於程式設計式的事務控制的配置檔案已經準備完畢,下面進行程式設計式開發。由於,我們把事務控制放在service層,下面是我的service層的程式碼
package com.cn.study.day5.service.inter.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import com.cn.study.day5.service.inter.AccountDaoInter;
import com.cn.study.day5.service.inter.AccountServiceIter;

@Component
public class AccountServiceImpl implements AccountServiceIter {
    @Autowired
    private AccountDaoInter adi;
    @Autowired
    private TransactionTemplate tt;
    //轉賬方法,由out向in轉money元
    @Override
    public void transfer(final String out, final String in, final double money) {
        // TODO Auto-generated method stub
    //使用事務管理器模板進行事務控制
    tt.execute(new TransactionCallbackWithoutResult() {

        @Override
        protected void doInTransactionWithoutResult(TransactionStatus status) {
            // TODO Auto-generated method stub
            adi.outMoney(out, money);
            //一個異常,使用了事務控制,在出現了異常之後,事務會回滾
            int i = 1 / 0;
            adi.inMoney(in, money);
        }
    });

}

}

由於是面向介面程式設計,這裡我只貼出了service層的實現,使用了自動掃描機制(掃描類、屬性上的註解@Component、@Autowired),transfer方法是實現轉賬的方法,首先從一個賬戶轉出,然後轉入另一個賬戶,使用事務管理器模板的execute方法,需要一個TransactionCallBack的例項,這裡使用匿名內部類的方式,把要執行的方法放在doInTransactionWithoutResult中執行,保證了事務的控制。

使用這種方式可以保證事務控制,但是在實際開發過程當中這種方式對程式碼的改動太大,不符合低侵入開發原則,所有這種方式在開發中幾乎很少用到,用的最多的是宣告式的事務控制。

二、宣告式事務控制

宣告式事務控制又分為三種方式,一、基於TransactionProxyFactoryBean代理的宣告式事務控制;二、使用AOP的宣告式事務控制;三、基於@Transactional註解的宣告式事務控制。

1、基於TransactionProxyFactoryBean的宣告式事務控制

TransactionProxyFactoryBean是事務的代理類,spring會為目標類生成一個代理,具體的配置如下,

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置業務層代理-->
<bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="target" ref="accountServiceImpl"></property>
    <property name="transactionManager" ref="transactionManager"></property>
    <property name="transactionAttributes">
        <props>
            <prop key="transfer"></prop>
        </props>
    </property>
</bean>

這裡只貼出了事務管理器和業務層代理的配置,剩餘的資料來源和業務類的配置可以執行配置,前面說到無論使用哪種方式配置事務管理,都需要使用事務管理器。重點看業務層代理,配置的class屬性為TransactionProxyFactoryBean,需要配置三個屬性:target(要代理的具體業務層實現類)、transactionManager(事務管理器)、transactionAttributes(要攔截的業務層方法)。配置完成之後,便可以進行測試,測試程式碼如下,

ApplicationContext ac=getApplicationContext();
AccountServiceIter asi=(AccountServiceIter)ac.getBean(“accountServiceProxy”);
asi.transfer(“aa”, “cc”, 10d);
通過getApplicationContext()方法獲得了ApplicationContext例項,然後獲得accountServiceProxy的例項,這裡獲得的不是AccountServiceImpl的例項而是代理的例項物件,因為使用代理,代理了實際的業務類,所有這裡不能再使用實際的類而應是代理類。

使用這種方式的需要為每一個需要使用事務的業務類配置一個代理比教麻煩,所以在開發過程中這種方式幾乎不用。

2、使用AOP的宣告式事務控制

這種方式是在開發過程中使用的比較多的一種,配置如下,

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事務增強-->
<tx:advice id="advicer" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="transfer*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>
<!--配置切點、事務通知-->
<aop:config>
    <aop:pointcut id="myPointcut" expression="execution(* com.cn.study.day555.service.inter.impl.*.*(..))"/>
    <aop:advisor advice-ref="advicer" pointcut-ref="myPointcut"/>
</aop:config>

配置了事務增強tx:advice配置對要增強的方法的事務的傳播行為等,配置aop:config配置切點和對應的事務通知,這樣就完成了AOP的宣告式事務控制。

3、基於@Transactional註解

使用@Transactional註解需要再配置檔案中開啟對這個註解的掃描:<tx:annotation-driven transaction-manager=“transactionManager” />,引用了事務管理器,然後就可以使用@Transactional註解,此註解可以使用在類上,也可以使用在方法上,使用在類上即對此類的所有方法都起作用,使用在方法上則表示對單個方法起作用,還可以配置一些屬性,放在另一篇文章中進行解釋。

通過對以上四種配置事務的方式的描述,其中宣告式方式中的第二種方式使用比較普通,對程式碼的侵入比較小,第三種因為配置簡單,也比較常用,但是需要在業務類或方法上加@Transcational註解,對程式碼有一定的侵入。