Spring事務處理


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

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

 

事務特性(ACID)

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

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

隔離性(Isolation):由並發事務所做的修改必須與任何其他事務所做的修改相隔離。事務查看數據時數據所處的狀態,要么是被另一並發事務修改之前的狀態,要么是被另一並發事務修改之后的狀態,即事務不會查看由另一個並發事務正在修改的數據。這種隔離方式也叫可串行性。

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

 

事務隔離(Isolation Level)

事務隔離意味着對於某一個正在運行的事務來說,好像系統中只有這一個事務,其他並發的事務都不存在一樣。

大部分情況下,很少使用完全隔離的事務。但不完全隔離的事務會帶來如下一些問題。

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

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

不可重讀(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事務處理原理

問題

       1、當JPA框架對數據庫進行操作的時候,是從那里獲取Connection?

       2、jdbc對事務的配置,比如事務的開啟,提交以及回滾是在哪里設置的?

       3、Spring是通過aop攔截切面的所有需要進行事務管理的業務處理方法,那如何獲取業務處理方法里面對數據庫操作的事務呢?

解答

      1、既然在JPA的框架里面配置了datasource,那自然會從這個datasource里面去獲得連接。

      2、jdbc的事務配置是在Connection對消里面有對應的方法,比如setAutoCommit,commit,rollback這些方法就是對事務的操作。

      3、Spring需要操作事務,那必須要對Connection來進行設置。Spring的AOP可以攔截業務處理方法,並且也知道業務處理方法里面的 DAO操作的JAP框架是從datasource里面獲取Connection對象,那么Spring需要對當前攔截的業務處理方法進行事務控制,那     必然 需要得到他內部的Connection對象。整體的結構圖如下:

           

源碼分析:略

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM