Spring事務處理

事務(Transaction是併發控制的單位,是用戶定義的一個操做序列。這些操做要麼都作,要麼都不作,是一個不可分割的工做單位。java

數據庫向用戶提供保存當前程序狀態的方法,叫事務提交(commit;當事務執行過程當中,使數據庫忽略當前的狀態並回到前面保存的狀態的方法叫事務回滾(rollbackspring

 

事務特性(ACID)

原子性(atomicity):將事務中所作的操做捆綁成一個原子單元,即對於事務所進行的數據修改等操做,要麼所有執行,要麼所有不執行。數據庫

一致性(Consistency):事務在完成時,必須使全部的數據都保持一致狀態,並且在相關數據中,全部規則都必須應用於事務的修改,以保持全部數據的完整性。事務結束時,全部的內部數據結構都應該是正確的。express

隔離性(Isolation):由併發事務所作的修改必須與任何其餘事務所作的修改相隔離。事務查看數據時數據所處的狀態,要麼是被另外一併發事務修改以前的狀態,要麼是被另外一併發事務修改以後的狀態,即事務不會查看由另外一個併發事務正在修改的數據。這種隔離方式也叫可串行性。服務器

持久性(Durability):事務完成以後,它對系統的影響是永久的,即便出現系統故障也是如此。session

 

事務隔離(Isolation Level)

事務隔離意味着對於某一個正在運行的事務來講,好像系統中只有這一個事務,其餘併發的事務都不存在同樣。數據結構

大部分狀況下,不多使用徹底隔離的事務。但不徹底隔離的事務會帶來以下一些問題。併發

更新丟失(Lost Update):兩個事務都企圖去更新一行數據,致使事務拋出異常退出,兩個事務的更新都白費了。框架

髒數據(Dirty Read):若是第二個應用程序使用了第一個應用程序修改過的數據,而這個數據處於未提交狀態,這時就會發生髒讀。第一個應用程序隨後可能會請求回滾被修改的數據,從而致使第二個事務使用的數據被損壞,即所謂的「變髒」。dom

不可重讀(Unrepeatable Read):一個事務兩次讀同一行數據,但是這兩次讀到的數據不同,就叫不可重讀。若是一個事務在提交數據以前,另外一個事務能夠修改和刪除這些數據,就會發生不可重讀。

幻讀(Phantom Read):一個事務執行了兩次查詢,發現第二次查詢結果比第一次查詢多出了一行,這多是由於另外一個事務在這兩次查詢之間插入了新行。針對由事務的不徹底隔離所引發的上述問題,提出了一些隔離級別,用來防範這些問題。

 

讀操做未提交(Read Uncommitted)讀取未提交的數據是容許的。說明一個事務在提交前,其變化對於其餘事務來講是可見的。這樣髒讀、不可重讀和幻讀都是容許的。當一個事務已經寫入一行數據但未提交,其餘事務都不能再寫入此行數據;可是,任何事務均可以讀任何數據。這個隔離級別使用排寫鎖實現。

讀操做已提交(Read Committed)讀取未提交的數據是不容許的,它使用臨時的共讀鎖和排寫鎖實現。這種隔離級別不容許髒讀,但不可重讀和幻讀是容許的。

可重讀(Repeatable Read):說明事務保證可以再次讀取相同的數據而不會失敗。此隔離級別不容許髒讀和不可重讀,但幻讀會出現。

 

可串行化(Serializable):提供最嚴格的事務隔離。這個隔離級別不容許事務並行執行,只容許串行執行。這樣,髒讀、不可重讀或幻讀均可發生。

 

 

1. 1事務隔離與隔離級別的關係

隔離級別

髒讀(Dirty Read)

不可重讀(Unrepeatable read)

幻讀(Phantom Read)

讀操做未提交(Read Uncommitted)

可能

可能

可能

讀操做已提交(Read Committed)

不可能

可能

可能

可重讀(Repeatable Read)

不可能

不可能

可能

可串行化(Serializable)

不可能

不可能

不可能

 

事務的傳播(Propagation)

 

事務傳播行爲類型

說明

PROPAGATION_REQUIRED

若是當前沒有事務,就新建一個事務,若是已經存在一個事務中,加入到這個事務中。這是 最多見的選擇。

PROPAGATION_SUPPORTS

支持當前事務,若是當前沒有事務,就以非事務方式執行。

PROPAGATION_MANDATORY

使用當前的事務,若是當前沒有事務,就拋出異常。

PROPAGATION_REQUIRES_NEW

新建事務,若是當前存在事務,把當前事務掛起。

PROPAGATION_NOT_SUPPORTED

以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。

PROPAGATION_NEVER

以非事務方式執行,若是當前存在事務,則拋出異常。

PROPAGATION_NESTED

若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則執行與 PROPAGATION_REQUIRED 相似的操做。

當使用 PROPAGATION_NESTED 時, 底層的數據源必須基於 JDBC 3.0 ,而且實現者須要支持保存點事務機制。

readOnly
    事務屬性中的readOnly標誌表示對應的事務應該被最優化爲只讀事務。這是一個最優化提示 。在一些狀況下,一些事務策略可以起到顯著的最優化效果,例如在使用Object/Relational映射工具 (如:Hibernate或TopLink)時避免dirty checking(試圖「刷新」)。

Timeout

     在事務屬性中還有定義「timeout」值的選項,指定事務超時爲幾秒。在JTA中,這將被簡單地傳遞到J2EE服務器的事務協調程序,並據此獲得相應的解釋。

例子:

 

 1 ServiceA {
 2 
 3     void methodA() {
 4         try {
 5         //savepoint
 6         ServiceB.methodB();
 7         } 
 8         catch (SomeException) {
 9         // 執行其餘業務, 如 ServiceC.methodC();
10         }
11     }
12 
13 }

1: PROPAGATION_REQUIRED

加入當前正要執行的事務不在另一個事務裏,那麼就起一個新的事務

例如

        ServiceB.methodB的事務級別定義爲PROPAGATION_REQUIRED

        ServiceA.methodA已經起了事務,這時調用ServiceB.methodB,ServiceB.methodB就加入ServiceA.methodA的事務內部,就再也不起新的事務。ServiceA.methodA沒有在事務中,這時調用ServiceB.methodB,

        ServiceB.methodB就會爲本身分配一個事務。

        在ServiceA.methodA或者在ServiceB.methodB內的任何地方出現異常,事務都會被回滾。即便ServiceB.methodB的事務已經被提交,可是ServiceA.methodA在接下來fail要回滾,ServiceB.methodB也要回滾

 

2: PROPAGATION_SUPPORTS

若是當前在事務中,即以事務的形式運行,若是當前再也不一個事務中,那麼就以非事務的形式運行

3: PROPAGATION_MANDATORY

必須在一個事務中運行。也就是說,他只能被一個父事務調用。不然,他就要拋出異常

4: PROPAGATION_REQUIRES_NEW

例如

        ServiceA.methodA的事務級別爲PROPAGATION_REQUIRED,ServiceB.methodB的事務級別爲PROPAGATION_REQUIRES_NEW,

        當調用ServiceB.methodB的時候,ServiceA.methodA所在的事務就會掛起,ServiceB.methodB會起一個新的事務,等待ServiceB.methodB的事務完成之後,他才繼續執行。

        PROPAGATION_REQUIRES_NEW與PROPAGATION_REQUIRED 的事務區別在於事務的回滾程度:

                由於ServiceB.methodB和ServiceA.methodA兩個不一樣的事務。若是ServiceB.methodB已經提交,那麼ServiceA.methodA失敗回滾,ServiceB.methodB是不會回滾的。若是ServiceB.methodB失敗回滾,

                若是他拋出的異常被ServiceA.methodA捕獲,ServiceA.methodA事務仍然可能提交。

 

5: PROPAGATION_NOT_SUPPORTED

當前不支持事務

例如:

  ServiceA.methodA的事務級別是PROPAGATION_REQUIRED ,而ServiceB.methodB的事務級別是PROPAGATION_NOT_SUPPORTED ,

  調用ServiceB.methodB時,ServiceA.methodA的事務掛起,而以非事務的狀態運行完,再繼續ServiceA.methodA的事務。

6: PROPAGATION_NEVER

不能在事務中運行

假設ServiceA.methodA的事務級別是PROPAGATION_REQUIRED,  而ServiceB.methodB的事務級別是PROPAGATION_NEVER ,

那麼ServiceB.methodB就要拋出異常了。

7: PROPAGATION_NESTED

理解Nested的關鍵是savepoint。他與PROPAGATION_REQUIRES_NEW的區別是,PROPAGATION_REQUIRES_NEW另起一個事務,將會與他的父事務相互獨立,

而Nested的事務和他的父事務是相依的,他的提交是要等和他的父事務一塊提交的。也就是說,若是父事務最後回滾,他也要回滾的。

而Nested事務的好處是他有一個savepoint。

 

Spring事務處理

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

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

具體以下圖:

    

 

第一種方式:每一個Bean都有一個代理

1.    <?xml version="1.0" encoding="UTF-8"?>  
2.    <beans xmlns="http://www.springframework.org/schema/beans"  
3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
4.        xmlns:context="http://www.springframework.org/schema/context"  
5.        xmlns:aop="http://www.springframework.org/schema/aop"  
6.        xsi:schemaLocation="http://www.springframework.org/schema/beans   
7.               http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
8.               http://www.springframework.org/schema/context  
9.               http://www.springframework.org/schema/context/spring-context-2.5.xsd  
10.               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  
11.      
12.        <bean id="sessionFactory"    
13.                class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">    
14.            <property name="configLocation" value="classpath:hibernate.cfg.xml" />    
15.            <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />  
16.        </bean>    
17.      
18.        <!-- 定義事務管理器(聲明式的事務) -->    
19.        <bean id="transactionManager"  
20.            class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
21.            <property name="sessionFactory" ref="sessionFactory" />  
22.        </bean>  
23.          
24.        <!-- 配置DAO -->  
25.        <bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">  
26.            <property name="sessionFactory" ref="sessionFactory" />  
27.        </bean>  
28.          
29.        <bean id="userDao"    
30.            class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">    
31.               <!-- 配置事務管理器 -->    
32.               <property name="transactionManager" ref="transactionManager" />       
33.            <property name="target" ref="userDaoTarget" />    
34.             <property name="proxyInterfaces" value="com.bluesky.spring.dao.GeneratorDao" />  
35.            <!-- 配置事務屬性 -->    
36.            <property name="transactionAttributes">    
37.                <props>    
38.                    <prop key="*">PROPAGATION_REQUIRED</prop>  
39.                </props>    
40.            </property>    
41.        </bean>    
42.    </beans>  

 

 第二種方式:全部Bean共享一個代理基類

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:context="http://www.springframework.org/schema/context"
 5     xmlns:aop="http://www.springframework.org/schema/aop"
 6     xsi:schemaLocation="http://www.springframework.org/schema/beans
 7            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 8            http://www.springframework.org/schema/context
 9            http://www.springframework.org/schema/context/spring-context-2.5.xsd
10            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
11 
12     <bean id="sessionFactory" 
13             class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
14         <property name="configLocation" value="classpath:hibernate.cfg.xml" /> 
15         <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
16     </bean> 
17 
18     <!-- 定義事務管理器(聲明式的事務) --> 
19     <bean id="transactionManager"
20         class="org.springframework.orm.hibernate3.HibernateTransactionManager">
21         <property name="sessionFactory" ref="sessionFactory" />
22     </bean>
23    
24     <bean id="transactionBase" 
25             class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" 
26             lazy-init="true" abstract="true"> 
27         <!-- 配置事務管理器 --> 
28         <property name="transactionManager" ref="transactionManager" /> 
29         <!-- 配置事務屬性 --> 
30         <property name="transactionAttributes"> 
31             <props> 
32                 <prop key="*">PROPAGATION_REQUIRED</prop> 
33             </props> 
34         </property> 
35     </bean>   
36   
37     <!-- 配置DAO -->
38     <bean id="userDaoTarget" class="com.bluesky.spring.dao.UserDaoImpl">
39         <property name="sessionFactory" ref="sessionFactory" />
40     </bean>
41    
42     <bean id="userDao" parent="transactionBase" > 
43         <property name="target" ref="userDaoTarget" />  
44     </bean>
45 </beans>

 

第三種方式:使用攔截器

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:context="http://www.springframework.org/schema/context"
 5     xmlns:aop="http://www.springframework.org/schema/aop"
 6     xsi:schemaLocation="http://www.springframework.org/schema/beans
 7            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 8            http://www.springframework.org/schema/context
 9            http://www.springframework.org/schema/context/spring-context-2.5.xsd
10            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
11 
12     <bean id="sessionFactory" 
13             class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
14         <property name="configLocation" value="classpath:hibernate.cfg.xml" /> 
15         <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
16     </bean> 
17 
18     <!-- 定義事務管理器(聲明式的事務) --> 
19     <bean id="transactionManager"
20         class="org.springframework.orm.hibernate3.HibernateTransactionManager">
21         <property name="sessionFactory" ref="sessionFactory" />
22     </bean> 
23   
24     <bean id="transactionInterceptor" 
25         class="org.springframework.transaction.interceptor.TransactionInterceptor"> 
26         <property name="transactionManager" ref="transactionManager" /> 
27         <!-- 配置事務屬性 --> 
28         <property name="transactionAttributes"> 
29             <props> 
30                 <prop key="*">PROPAGATION_REQUIRED</prop> 
31             </props> 
32         </property> 
33     </bean>
34      
35     <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
36         <property name="beanNames"> 
37             <list> 
38                 <value>*Dao</value>
39             </list> 
40         </property> 
41         <property name="interceptorNames"> 
42             <list> 
43                 <value>transactionInterceptor</value> 
44             </list> 
45         </property> 
46     </bean> 
47  
48     <!-- 配置DAO -->
49     <bean id="userDao" class="com.bluesky.spring.dao.UserDaoImpl">
50         <property name="sessionFactory" ref="sessionFactory" />
51     </bean>
52 </beans>

 

第四種方式:使用tx標籤配置的攔截器

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:context="http://www.springframework.org/schema/context"
 5     xmlns:aop="http://www.springframework.org/schema/aop"
 6     xmlns:tx="http://www.springframework.org/schema/tx"
 7     xsi:schemaLocation="http://www.springframework.org/schema/beans
 8            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 9            http://www.springframework.org/schema/context
10            http://www.springframework.org/schema/context/spring-context-2.5.xsd
11            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
12            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
13 
14     <context:annotation-config />
15     <context:component-scan base-package="com.bluesky" />
16 
17     <bean id="sessionFactory" 
18             class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
19         <property name="configLocation" value="classpath:hibernate.cfg.xml" /> 
20         <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
21     </bean> 
22 
23     <!-- 定義事務管理器(聲明式的事務) --> 
24     <bean id="transactionManager"
25         class="org.springframework.orm.hibernate3.HibernateTransactionManager">
26         <property name="sessionFactory" ref="sessionFactory" />
27     </bean>
28 
29     <tx:advice id="txAdvice" transaction-manager="transactionManager">
30         <tx:attributes>
31             <tx:method name="*" propagation="REQUIRED" />
32         </tx:attributes>
33     </tx:advice>
34    
35     <aop:config>
36         <aop:pointcut id="interceptorPointCuts"
37             expression="execution(* com.bluesky.spring.dao.*.*(..))" />
38         <aop:advisor advice-ref="txAdvice"
39             pointcut-ref="interceptorPointCuts" />       
40     </aop:config>     
41 </beans>

 

第五種方式:全註解

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:context="http://www.springframework.org/schema/context"
 5     xmlns:aop="http://www.springframework.org/schema/aop"
 6     xmlns:tx="http://www.springframework.org/schema/tx"
 7     xsi:schemaLocation="http://www.springframework.org/schema/beans
 8            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 9            http://www.springframework.org/schema/context
10            http://www.springframework.org/schema/context/spring-context-2.5.xsd
11            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
12            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
13 
14     <context:annotation-config />
15     <context:component-scan base-package="com.bluesky" />
16 
17     <tx:annotation-driven transaction-manager="transactionManager"/>
18 
19     <bean id="sessionFactory" 
20             class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
21         <property name="configLocation" value="classpath:hibernate.cfg.xml" /> 
22         <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
23     </bean> 
24 
25     <!-- 定義事務管理器(聲明式的事務) --> 
26     <bean id="transactionManager"
27         class="org.springframework.orm.hibernate3.HibernateTransactionManager">
28         <property name="sessionFactory" ref="sessionFactory" />
29     </bean>
30    
31 </beans>

 

此時在DAO上需加上@Transactional註解,以下:

package com.bluesky.spring.dao;

import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Component;

import com.bluesky.spring.domain.User;

@Transactional
@Component("userDao")
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {

    public List<User> listUsers() {
        return this.getSession().createQuery("from User").list();
    }
   
   
}

Spring事務處理原理

問題

       一、當JPA框架對數據庫進行操做的時候,是從那裏獲取Connection?

       二、jdbc對事務的配置,好比事務的開啓,提交以及回滾是在哪裏設置的?

       三、Spring是經過aop攔截切面的全部須要進行事務管理的業務處理方法,那如何獲取業務處理方法裏面對數據庫操做的事務呢?

解答

      一、既然在JPA的框架裏面配置了datasource,那天然會從這個datasource裏面去得到鏈接。

      二、jdbc的事務配置是在Connection對消裏面有對應的方法,好比setAutoCommit,commit,rollback這些方法就是對事務的操做。

      三、Spring須要操做事務,那必需要對Connection來進行設置。Spring的AOP能夠攔截業務處理方法,而且也知道業務處理方法裏面的 DAO操做的JAP框架是從datasource裏面獲取Connection對象,那麼Spring須要對當前攔截的業務處理方法進行事務控制,那     必然 須要獲得他內部的Connection對象。總體的結構圖以下:

           

源碼分析:略

相關文章
相關標籤/搜索