Spring 事務概括

Spring transaction

什麼是事務

A用戶向B用戶轉賬100,第一步要從A賬戶扣出100,第二步要將B賬戶加上100。其中不管是第一步失敗,仍是第二步失敗。都應該將A、B賬戶的餘額保持和轉賬操做以前一致。
事務就是一系列相關聯操做的集合,一個事務能夠是多個步驟組成,若是一個步驟失敗,那麼整個流程都應該回滾到初始狀態。java

事務的四個特性

  • 原子性(Atomicity) 一個事務是一個總體,不管有多少個步驟組成,要麼全部步驟都成功,要麼全部步驟都失敗。
  • 一致性(Consistency) 一個事務完成(不管是成功仍是失敗),全部的業務都應該處於一致的狀態,不該該部分步驟成功,部分步驟失敗,顯示中的數據一致性不會被破壞。
  • 隔離性(Isolation) 多個事務處理相同的數據的時候,事務間應該是相互隔離的,防止數據損壞。
  • 持久性(Durability) 一旦事務完成,不管系統發生什麼異常,結果都不該該受到影響,一般事務的結果被寫入到數據庫中。

Spring處理事務的核心接口

Spring涉及到事務管理的核心接口相互關係以下

Spring並無直接提供事務管理的實現,而是提供了一個接口PlatformTransactionManager。具體的實現依賴項目中所使用的持久化接口。

PlatformTransactionManager 定義了全部的具體實現類必需要有的方法

  • 經過TransactionDefinition獲取TransactionStatus
  • commit 提交事務
  • rollback 回滾事務spring

    TransactionDefinition接口

    TransactionDefinition主要包含的屬性和方法

  • 事務的傳播級別
  • 事務的隔離級別
  • 事務超時
  • 只讀狀態sql

    TransactionStatus接口

以上能夠看到事務的具體實現能夠有四種

  • 使用JDBC事務,添加配置的方式爲
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="dataSource" />
   </bean>
  • 使用Hibernate事務,添加配置的方式爲
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
     <property name="sessionFactory" ref="sessionFactory" />
   </bean>
  • 使用JAVA持久化API事務(JPA)
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
       <property name="sessionFactory" ref="sessionFactory" />
   </bean>
  • JAVA原生API事務 若是沒有使用以上任何一個實現,或者是使用了多個事務管理源(使用了多個數據源)
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
       <property name="transactionManagerName" value="java:/TransactionManager" />
    </bean>

事務屬性的定義

事務的傳播級別

在上面TransactionDefinition接口中能夠看到,一共有7個級別數據庫

  • PROPAGATION_REQUIRED 當前方法必須運行在事務中,已經有事務,則在當前事務中;沒有事務,會新建一個事務。
  • PROPAGATION_SUPPORTS 當前方法能夠運行在事務中,已經有事務,則在當前事務中;沒有事務,不會建立新事務。
  • PROPAGATION_MANDATORY 當前方法必須運行在事務中,若是沒有事務,會拋出異常。
  • PROPAGATION_REQUIRES_NEW 當前方法必須運行在本身的事務中,已經有事務,則將當前事務掛起,新建一個事務;沒有事務,會新建一個事務。(若是使用JTATransactionManager的話,則須要訪問TransactionManager)
  • PROPAGATION_NOT_SUPPORTED 當前方法 不支持 運行在事務中,已經有事務,將當前事務掛起(若是使用JTATransactionManager的話,則須要訪問TransactionManager)
  • PROPAGATION_NEVER 當前方法不能運行在事務中,已經有事務,會拋出異常。
  • PROPAGATION_NESTED 表示若是當前已經存在一個事務,那麼該方法將會在嵌套事務中運行。嵌套的事務能夠獨立於當前事務進行單獨地提交或回滾。若是當前事務不存在,那麼其行爲與PROPAGATION_REQUIRED同樣

原生JDBC的事務

代碼展現瞭如何經過將Connection設置成conn.setAutoCommit(false),而後在代碼執行成功以後再經過conn.commit()方法來提交,或者是conn.rollback()來回滾操做。express

public class Demo {
    public static void main(String[] args) {
        test1();
    }

    public static Connection getConn() {
        String driver = "oracle.jdbc.OracleDriver";
        String url = "jdbc:oracle:thin:@xxxxx";
        String username = "username";
        String password = "password";
        Connection conn = null;
        try{
            Class.forName(driver);
            conn = (Connection) DriverManager.getConnection(url, username, password);
        }catch (Exception e){
            e.printStackTrace();
        }
        return conn;
    }

    public static void test1() {
        Connection conn = getConn();
        Random random = new Random();
        int id = random.nextInt(100);
        System.out.println("--------id is "+id+"--------");
        String sql = "insert into test (ID,NAME) values(?,?)";
        PreparedStatement pstmt;
        try {
            conn.setAutoCommit(false);
            pstmt = (PreparedStatement) conn.prepareStatement(sql);
            pstmt.setString(1, id+"");
            pstmt.setString(2, "haha");

            pstmt.executeUpdate();
            if(id%2==0){
                System.out.println("--------even num--------");
                int error = 9/0;
            }else{
                System.out.println("--------odd num--------");
            }
            conn.commit();
            pstmt.close();
            conn.close();
            System.out.println("----------commit-------------");
        } catch (Exception e) {
            try {
                conn.rollback();
                System.out.println("----------rollback-------------");
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }
    }
}

事務的傳播級別詳解—REQUIRED

  • 場景1
class Demo{
    @Transactional(propagation = Propagation.REQUIRED)
    methodB();
}

若是此時單獨調用methodB(),剛進入方法的時候,是沒有事務的;而後因爲註解上的事務傳播級別是REQUIRED;因此此時Spring會默認建立一個事務,將methodB()內的全部操做放在一個事務內。編程

  • 場景2
class Demo{
    @Transactional(propagation = Propagation.REQUIRED)
    methodA(){
        methodB();
    }

    @Transactional(propagation = Propagation.REQUIRED)
    methodB();
}

此時若是調用methodA(),Spring一樣會爲methodA()上新建一個事務,而後再調用methodB()時,因爲已經存在事務,此時methodB()將在已有的事務中運行。Spring會保證methodB()內全部操做數據庫使用的鏈接是和methodA()中使用到的數據庫鏈接是同一個。後端

事務的傳播級別詳解—SUPPORTS

  • 場景1
class Demo{
    @Transactional(propagation = Propagation.SUPPORTS)
    methodB();
}

單獨調用methodB(),因爲默認沒有事務,因此方法就不會有事務的存在。session

  • 場景2
class Demo{
    @Transactional(propagation = Propagation.REQUIRED)
    methodA(){
        methodB();
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    methodB();
}

此時若是調用methodA(),Spring一樣會爲methodA()上新建一個事務,而後再調用methodB()時,因爲已經存在事務,此時methodB()將在已有的事務中運行。併發

事務的傳播級別詳解—MANDATORY

  • 場景1
class Demo{
    @Transactional(propagation = Propagation.MANDATORY)
    methodB();
}

單獨調用methodB(),因爲默認沒有事務,此時會報錯。oracle

  • 場景2
class Demo{
    @Transactional(propagation = Propagation.REQUIRED)
    methodA(){
        methodB();
    }

    @Transactional(propagation = Propagation.MANDATORY)
    methodB();
}

經過methodA()來調用methodB(),因爲methodA()中有事務,methodB()將運行在已有的事務中。

事務的傳播級別詳解—REQUIRES_NEW

  • 場景1
class Demo{
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    methodB();
}

單獨調用methodB(),因爲默認沒有事務,會新建立一個事務。

  • 場景2
class Demo{
    @Transactional(propagation = Propagation.REQUIRED)
    methodA(){
        methodB();
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    methodB();
}

經過methodA()來調用methodB(),因爲methodA()中有事務,methodB()將會把已有的事務掛起,新建立一個事務,methodB()將運行在新建立的事務中。methodB()和methodA()相互的運行結果不會由於對方失敗而回滾,由於他們是在兩個相互獨立的事務中。若是要使用PROPAGATION_REQUIRES_NEW,須要使用 JtaTransactionManager做爲事務管理器。

事務的傳播級別詳解—NEVER

方法決不能運行在事務中,若是有事務存在,則會拋出異常。

事務的傳播級別詳解—NESTED

  • 場景1
class Demo{
    @Transactional(propagation = Propagation.NESTED)
    methodB();
}

單獨調用methodB(),行爲和Propagation.REQUIRED同樣,因爲默認沒有事務,會新建立一個事務。

  • 場景2
class Demo{
    @Transactional(propagation = Propagation.REQUIRED)
    methodA(){
        funBefore();
        methodB();
        funAfter();
    } 

    @Transactional(propagation = Propagation.NESTED)
    methodB();
}

嵌套事務一個很是重要的概念就是內層事務依賴於外層事務。外層事務失敗時,會回滾內層事務所作的動做。而內層事務操做失敗並不會引發外層事務的回滾。

PROPAGATION_NESTED 與PROPAGATION_REQUIRES_NEW的區別

若是不存在事務,二者的行爲和PROPAGATION_REQUIRES一致,都會建立一個新的事務。
若是已存在事務,二者也都會新建立一個事務。

  • PROPAGATION_REQUIRES_NEW註解中,內外層事務不會相互影響,內層事務開啓的時候,外層事務是掛起的,內外層事務部是用的同一個數據訪問鏈接,能夠看做兩個獨立的事務,任何一方失敗都不會對另外一方形成影響。
  • PROPAGATION_NESTED註解中,內部事務和外部事務使用的是同一個數據訪問鏈接,只是在內部事務開啓以前,會建立一個Savepoint,內部事務回滾,會回滾到這個Savepoint;外部事物若是回滾,會連帶內部事務一塊兒回滾,應爲內部事務完成以後並無提交事務。

因而可知, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大區別在於, PROPAGATION_REQUIRES_NEW 徹底是一個新的事務, 而 PROPAGATION_NESTED 則是外部事務的子事務, 若是外部事務 commit, 嵌套事務也會被 commit, 這個規則一樣適用於 roll back.

事務的隔離級別

事務之間併發可能產生的後果

  • 髒讀

    發生在一個事務讀取了另外一個事務改寫但還沒有提交的數據時。若是改寫在稍後被回滾了,那麼第一個事務獲取的數據就是無效的。

  • 不可重複讀

    不可重複讀發生在一個事務執行相同的查詢兩次或兩次以上,可是每次都獲得不一樣的數據時。這一般是由於另外一個併發事務在兩次查詢期間進行了更新。

  • 幻讀

    幻讀與不可重複讀相似。它發生在一個事務(T1)讀取了幾行數據,接着另外一個併發事務(T2)插入了一些數據時。在隨後的查詢中,第一個事務(T1)就會發現多了一些本來不存在的記錄。

    幻讀與不可重複讀的區別在於, 不可重複讀常指一條記錄,幾回的查詢結果不一致。幻讀常指某一查詢條件的結果的個數,屢次查詢後結果不一致。

    隔離級別 含義
    ISOLATION_DEFAULT 使用數據庫的默認隔離級別
    ISOLATION_READ_UNCOMMITTED 最低的隔離級別,容許讀取到還沒有COMMIT的數據,會致使髒讀,幻讀和不可重複讀
    ISOLATION_READ_COMMITTED 容許讀取併發事務已經COMMIT的事務,能夠阻止髒讀,可是幻讀和不可重複讀還會發生
    ISOLATION_REPEATABLE_READ 對同一字段的屢次讀取結果都是一致的,除非數據是被自己事務本身所修改,能夠阻止髒讀和不可重複讀,但幻讀仍有可能發生
    ISOLATION_SERIALIZABLE 最高的隔離級別,徹底服從ACID的隔離級別,確保阻止髒讀、不可重複讀以及幻讀,也是最慢的事務隔離級別,由於它一般是經過徹底鎖定事務相關的數據庫表來實現的

只讀

事務超時 

爲了使應用程序很好地運行,事務不能運行太長的時間。由於事務可能涉及對後端數據庫的鎖定,因此長時間的事務會沒必要要的佔用數據庫資源。事務超時就是事務的一個定時器,在特定時間內事務若是沒有執行完畢,那麼就會自動回滾,而不是一直等待其結束。

回滾規則

這些規則定義了哪些異常會致使事務回滾而哪些不會。默認狀況下,事務只有遇到運行期異常時纔會回滾,而在遇到檢查型異常時不會回滾,可是你能夠聲明事務在遇到特定的檢查型異常時像遇到運行期異常那樣回滾。一樣,你還能夠聲明事務遇到特定的異常不回滾,即便這些異常是運行期異常。

事務狀態

這個接口描述的是一些處理事務提供簡單的控制事務執行和查詢事務狀態的方法,在回滾或提交的時候須要應用對應的事務狀態。

public interface TransactionStatus{
    boolean isNewTransaction(); // 是不是新的事物
    boolean hasSavepoint(); // 是否有恢復點
    void setRollbackOnly();  // 設置爲只回滾
    boolean isRollbackOnly(); // 是否爲只回滾
    boolean isCompleted; // 是否已完成
}

3 如何使用事務

3.1 編程式事務和聲明式事務的區別

  • 編程式事務,須要將事務控制的代碼與業務邏輯寫在一塊兒,優勢是能夠精準的控制事務的行爲、缺點就是有非業務代碼侵入。
  • 聲明式事務,將事務的控制經過Spring AOP來實現,優勢是沒有代碼侵入,只須要在使用事務的地方添加註解,缺點是配置複雜。

3.2 編程式事務

3.2.1 使用TransactionTemplate實現的編程式事務

TransactionTemplate tt = new TransactionTemplate(); // 新建一個TransactionTemplate
Object result = tt.execute(
    new TransactionCallback(){  
        public Object doTransaction(TransactionStatus status){  
            updateOperation();  
            return resultOfUpdateOperation();  
        }  
}); // 執行execute方法進行事務管理

或者是

TransactionTemplate tt = new TransactionTemplate(); // 新建一個TransactionTemplate
Object result = tt.execute(
    new TransactionCallbackWithoutResult(){
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
            // call dao
        }
}); // 執行execute方法進行事務管理

3.2.2 使用PlatformTransactionManager實現的編程式事務

DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); //定義一個某個框架平臺的TransactionManager,如JDBC、Hibernate
dataSourceTransactionManager.setDataSource(this.getJdbcTemplate().getDataSource()); // 設置數據源
DefaultTransactionDefinition transDef = new DefaultTransactionDefinition(); // 定義事務屬性
transDef.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); // 設置傳播行爲屬性
TransactionStatus status = dataSourceTransactionManager.getTransaction(transDef); // 得到事務狀態
try {
    // 數據庫操做
    dataSourceTransactionManager.commit(status);// 提交
} catch (Exception e) {
    dataSourceTransactionManager.rollback(status);// 回滾
}

3.3 配置式事務

Spring配置文件中關於事務配置老是由三個組成部分,分別是DataSource、TransactionManager和代理機制這三部分,不管哪一種配置方式,通常變化的只是代理機制這部分。

DataSource、TransactionManager這兩部分只是會根據數據訪問方式有所變化,好比使用Hibernate進行數據訪問時,DataSource實際爲SessionFactory,TransactionManager的實現爲HibernateTransactionManager。

具體以下圖:

123

3.3.1 每一個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:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

    <bean id="sessionFactory"  
            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
        <property name="configLocation" value="classpath:hibernate.cfg.xml" />  
        <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
    </bean>  

    <!-- 定義事務管理器(聲明式的事務) -->  
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    
    <!-- 配置DAO -->
    <bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    
    <bean id="userDao"  
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">  
           <!-- 配置事務管理器 -->  
           <property name="transactionManager" ref="transactionManager" />     
        <property name="target" ref="userDaoTarget" />  
         <property name="proxyInterfaces" value="com.bluesky.spring.dao.GeneratorDao" />
        <!-- 配置事務屬性 -->  
        <property name="transactionAttributes">  
            <props>  
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>  
        </property>  
    </bean>  
</beans>

3.3.2 全部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:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

    <bean id="sessionFactory"  
            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
        <property name="configLocation" value="classpath:hibernate.cfg.xml" />  
        <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
    </bean>  

    <!-- 定義事務管理器(聲明式的事務) -->  
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    
    <bean id="transactionBase"  
            class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"  
            lazy-init="true" abstract="true">  
        <!-- 配置事務管理器 -->  
        <property name="transactionManager" ref="transactionManager" />  
        <!-- 配置事務屬性 -->  
        <property name="transactionAttributes">  
            <props>  
                <prop key="*">PROPAGATION_REQUIRED</prop>  
            </props>  
        </property>  
    </bean>    
   
    <!-- 配置DAO -->
    <bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    
    <bean id="userDao" parent="transactionBase" >  
        <property name="target" ref="userDaoTarget" />   
    </bean>
</beans>

3.3.3 使用攔截器

<?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:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

    <bean id="sessionFactory"  
            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
        <property name="configLocation" value="classpath:hibernate.cfg.xml" />  
        <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
    </bean>  

    <!-- 定義事務管理器(聲明式的事務) -->  
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean> 
   
    <bean id="transactionInterceptor"  
        class="org.springframework.transaction.interceptor.TransactionInterceptor">  
        <property name="transactionManager" ref="transactionManager" />  
        <!-- 配置事務屬性 -->  
        <property name="transactionAttributes">  
            <props>  
                <prop key="*">PROPAGATION_REQUIRED</prop>  
            </props>  
        </property>  
    </bean>
      
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">  
        <property name="beanNames">  
            <list>  
                <value>*Dao</value>
            </list>  
        </property>  
        <property name="interceptorNames">  
            <list>  
                <value>transactionInterceptor</value>  
            </list>  
        </property>  
    </bean>  
  
    <!-- 配置DAO -->
    <bean id="userDao" class="com.bluesky.spring.dao.UserDaoImpl">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
</beans>

3.3.4 使用tx標籤配置的攔截器

<?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: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/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.bluesky" />

    <bean id="sessionFactory"  
            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
        <property name="configLocation" value="classpath:hibernate.cfg.xml" />  
        <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
    </bean>  

    <!-- 定義事務管理器(聲明式的事務) -->  
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>
    
    <aop:config>
        <aop:pointcut id="interceptorPointCuts"
            expression="execution(* com.bluesky.spring.dao.*.*(..))" />
        <aop:advisor advice-ref="txAdvice"
            pointcut-ref="interceptorPointCuts" />        
    </aop:config>      
</beans>

3.3.5 全註解

<?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: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/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.bluesky" />

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <bean id="sessionFactory"  
            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
        <property name="configLocation" value="classpath:hibernate.cfg.xml" />  
        <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
    </bean>  

    <!-- 定義事務管理器(聲明式的事務) -->  
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    
</beans>

4 一個聲明式事務的實例

//todo

相關文章
相關標籤/搜索