轉:Spring中事物管理

1.什麼是事務?

事務是邏輯上的一組操做,這組操做要麼所有成功,要麼所有失敗html

2.事物具備四大特性ACID

說到事務,就不得不說其4大特性,主要以下

原子性:(atomicity)
原子性指的是事務是一個不可分割的工做單位,事務中的操做要麼所有發生,要麼都不發生
(就像物理中,原子是最小不可分割的單位)
一致性:(consistency)
一致性指的是事務先後數據的完整性必須保持一致(好比說,轉帳:張三帳戶有2000元,李四帳戶有2000元,一共4000元
張三項李四轉帳2000元后,一共仍是4000元)
事務必須是使數據庫從一個一致性狀態變到另外一個一致性狀態。一致性與原子性是密切相關的
隔離性:(isolation)
隔離性指的是多個用戶併發訪問數據庫是,一個用戶的事務不能被其餘用戶的事務
干擾,多個併發事務之間相互隔離
持久性:(durability)。
持久性指的是一個事務一旦被提交,他對數據庫中的數據的改變是永久的,即便數據庫故障
也不該該對其有任何影響
java

3.Spring中事務的管理

Spring中主要提供瞭如下3個接口來對事務進行管理

PlatformTransactionManager 平臺事務管理器
主要用於事務的提交,回滾等說明
TransactionDefintion  事務定義信息(隔離,傳播,超時,只讀)
主要用於事務的隔離,傳播,只讀等說明
TransactionStatus  事務具體運行狀態
是不是一個新的事務,是否有保存點,事務是否完成等說明

大體的運行過程:
首先經過TransactionDefinition定義了事務(隔離,傳播,超時,只讀)等信息後,再交給PlatformTransactionManager平臺事務管理器進行真正的事務管理,以後事務會產生一些相應的狀態,以後就會保存到TransactionStatus中。

3.1平臺事務管理器PlatformTransactionManager

主要定義了各個不一樣的數據庫平臺的一些接口,針對不一樣的數據庫平臺進行事務管理

org.springframework.jdbc.datasource.DataSourceTransactionManager   使用jdbc或Mybatis進行持久化時使用
org.springframework.orm.hibernate3.HibernateTransactionManager使用Hibernate3.0版本進行持久化數據時使用
org.springframework.orm.jdo.JdoTransactionManager 持久化機制爲jdao
org.springframework.orm.jpa.JpaTransactionManager 使用jpa進行持久化
org.springframework.transaction.jta.JtaTransactionManager使用JTA來實現事務管理,在一個事務跨越多個資源時必須使用

咱們再使用不一樣的數據庫時候,能夠選擇不一樣事務管理器,還有這裏列舉了一些經常使用的,還有其餘的能夠參見SpringApi說明,也能夠查看在線api:  http://tool.oschina.net/apidocs/#S


3.2事務定義信息接口 TransactionDefintion 

主要用於聲明事務的傳播行爲,和隔離級別等信息
假如一個事務不去考慮其隔離性,可能會引起以下問題(髒讀,不可重複讀,幻讀)
3.2.1事務的髒讀,不可重複讀,幻讀
髒讀:一個事務讀取到了一個事務 改寫可是未提交的數據,若是這些數據回滾,則讀取到的數據是無效的
不可重複讀:在同一個事物中,屢次讀取同一數據,因爲另一個事務對該數據 修改提交,形成返回的結果不一樣。
幻讀(虛讀):一個事務讀取幾行記錄後,另外一個事務 插入或刪除 了一些記錄,致使再次讀取的返回結果不一樣。

不可重複讀和幻讀,很類似,只是側重點不一樣:
相同點都是一個事務讀取了另外一個提交了的數據
不一樣點在於,不可重複讀側重點在於修改並提提交,幻讀(虛度)在於刪除或添加
能夠參見博文:http://blog.csdn.net/v123411739/article/details/39298127
3.2.2 事務的隔離級別
爲了解決上訴問題,Spring在接口TransactionDefintion中定義了4中隔離級別,以下:
DEFAULT 使用數據默認的隔離級別(由spring根據使用的數據決定)
READ_UNCOMMITED容許你讀取還未提交的改變了的數據(可致使髒讀,幻讀,不可重複讀)
READ_COMMINTED容許你讀取事務已經提交後的數據(可防止髒讀,可是幻讀和不可重複讀是有可能發生的) 
REPEATABLE_READ對相同字段的屢次讀取是一致的,除非數據被事務自己改變(可防止髒讀,不可重複讀,當幻讀任然可能發生)
SERIALIZABLE 徹底服從ACID的隔離級別,確保不發生髒讀,幻讀,不可重複讀。這在全部的隔離級別中是最慢的,他是典型的
經過徹底鎖定在事務中設計的數據表來完成的
 
提示:oracle默認的是:READ_COMMINTEDmysql默認是:REPEATABLE_READ,前邊的3個是咱們常常須要使用的

3.2.3事務的傳播行爲
通常咱們的事務是在業務層中(Service)中使用的,假如遇到比較複雜的業務,須要在一個業務中調用另外一個業務的方法:

以下:
業務邏輯ServiceA中的方法methoda()中的須要與業務邏輯ServiceB中的方法methodb()方法共同完成某個複雜的邏輯
假如都有事務,究竟是使用誰的事務。
事務的傳播行爲,正是爲了解決業務層中的方法相互調用的問題 的。
[java] view plain copy
  1. <span style="white-space:pre">        </span>ServiceA{   
  2.             methoda(){//須要調用serviceB中的業務方法methodb()共同完成  
  3.                 dao1.xxmethod();  
  4.                 serviceB.methodb();  
  5.                   
  6.             }  
  7.         }  
  8.           
  9.         ServiceB{  
  10.             methodb(){  
  11.                 dao2.yymethod();  
  12.             }  
  13.         }  
  14.   
  15.         DAO1{  
  16.             xxmethod(){  
  17.               
  18.             }  
  19.         }  
  20.   
  21.         DAO2{  
  22.             yymethod(){  
  23.   
  24.             }  
  25.   
  26.         }  

Spring的事務定義信息接口TransactionDefintion還定義了以下7中事務傳播行爲常量,咱們能夠分爲3類,(同一事物中,不一樣事務中,嵌套事務中)

類一,兩種在同一事物中
PROPAGATION_REQUIRED--支持當前事務,若是當前沒有事務,就新建一個事務。這是最多見的選擇。(就好比上邊的場景,methoda假若有事務
則使用methoda的使用,假如methoda沒有則新建一個事務)
PROPAGATION_SUPPORTS--支持當前事務,若是當前沒有事務,就以非事務方式執行。(就好比上邊的場景,methoda假若有事務
則使用methoda的使用,假如methoda沒有則不使用事務)
PROPAGATION_MANDATORY--支持當前事務,若是當前沒有事務,就拋出異常。(就好比上邊的場景,methoda假若有事務
則使用methoda的使用,假如methoda沒有則拋出異常) 
類二,二者再也不同一個事物中
PROPAGATION_REQUIRES_NEW--新建事務,若是當前存在事務,把當前事務掛起。(就好比上邊的場景,methoda假若有事務掛起該事物
不使用,而methodb新建一個事務) 
PROPAGATION_NOT_SUPPORTED--以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。(就好比上邊的場景,methoda假若有事務掛起該事物
不使用,而methodb不使用事務)  
PROPAGATION_NEVER--以非事務方式執行,若是當前存在事務,則拋出異常。(就好比上邊的場景,methoda假若有事務則拋出異常)  

類三嵌套事務中
PROPAGATION_NESTED 若是當前事務存在,則嵌套事務執行(若是在執行methoda完成的時候,就會使用事務設置一個保存點,再執行methodb,假如methodb沒有異常,他們就一塊兒提交了,若是
發生了異常,你可根據本身的設定你可選擇回滾到保存點位置,也能夠回滾到最初的狀態)  

3.3  事務具體運行狀態接口 TransactionStatus 

裏邊主要定義了事務運行過程的一些具體狀態(如是不是新的事務,是否只讀,是否設置保存點)等等,這些都是能夠得到的

4.Spring中的事務實現方式

Spring主要經過以下兩種方式進行事務管理
-編程式事務管理
主要經過TransactionTemplate手動管理事務,在實際開發中不多使用
-使用XML配置聲明
主要經過Spring的AOP實現的,在開發中推薦使用(代碼入侵性小)

4.1Spring的編程式事務管理

所謂編程式事務指的是經過編碼方式實現事務,即相似於JDBC編程實現事務管理。
管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。
對於編程式事務管理,spring推薦使用TransactionTemplate。

這裏咱們經過轉帳的小案例來實現:

account帳戶表:
  1. create table account(  
  2.     id number(20) primary key,  
  3.     name varchar2(20),  
  4.     money number  
  5. );  
  6.   
  7. insert into account values(1,'張三',1000);  
  8. insert into account values(2,'李四',1000);  
  9. insert into account values(3,'王五',1000);  

外部文件db.properties
[plain] view plain copy
  1. jdbc.driver=oracle.jdbc.driver.OracleDriver  
  2. jdbc.url=jdbc:oracle:thin:@localhost:1521:XE  
  3. jdbc.username=xxx  
  4. jdbc.password=xxx  

配置文件applicationContext.xml
[html] view plain copy
  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" xmlns:context="http://www.springframework.org/schema/context"  
  4.     xmlns:aop="http://www.springframework.org/schema/aop"  
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans   
  6.  http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
  7.  http://www.springframework.org/schema/aop   
  8.  http://www.springframework.org/schema/aop/spring-aop-3.2.xsd  
  9.  http://www.springframework.org/schema/context    
  10.       http://www.springframework.org/schema/context/spring-context.xsd">  
  11.         
  12.       <!-- 引入外部文件 -->  
  13.      <context:property-placeholder location="classpath:db.properties"/>  
  14.        
  15.      <!-- 配置c3p0的鏈接池 -->  
  16.      <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  
  17.         <property name="driverClass">  
  18.             <value>${jdbc.driver}</value>  
  19.         </property>  
  20.         <property name="jdbcUrl">  
  21.             <value>${jdbc.url}</value>  
  22.         </property>  
  23.         <property name="user">  
  24.             <value>${jdbc.username}</value>  
  25.         </property>  
  26.         <property name="password">  
  27.             <value>${jdbc.password}</value>  
  28.         </property>  
  29.      </bean>  
  30.        
  31.      <!-- 配置業務層的類 -->  
  32.      <bean id="accountService" class="com.xxx.spring.chap5.service.impl.AccountServiceImpl">  
  33.         <property name="accountDao" ref="accountDao"></property>  
  34.         <!-- 注入事務管理模板 -->  
  35.         <property name="transactionTemplate" ref="transactionTemplate"></property>  
  36.      </bean>  
  37.      <!-- 配置dao,Dao繼承了JdbcDaoSupport後,只要注入了鏈接池就會有模板,就能夠經過模板對數據庫進行相應的操做,能夠參見源碼-->  
  38.      <bean id="accountDao" class="com.xx.spring.chap5.dao.impl.AccountDaoImpl">  
  39.         <property name="dataSource" ref="dataSource"></property>  
  40.      </bean>  
  41.        
  42.      <!-- 配置事務管理 -->  
  43.      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  44.         <property name="dataSource" ref="dataSource"></property>  
  45.      </bean>  
  46.        
  47.      <!-- 配置事務管理模板,Spring爲了簡化事務管理的代碼,提供了事務管理模板 -->  
  48.      <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">  
  49.         <property name="transactionManager" ref="transactionManager"></property>  
  50.      </bean>  
  51. </beans>  

Service:業務邏輯接口
[java] view plain copy
  1. /** 
  2.  * 轉帳的業務接口 
  3.  * */  
  4. public interface AccountService {  
  5.       
  6.     /** 
  7.      * @param out 轉出的帳戶 
  8.      * @param in 轉入的帳戶 
  9.      * @param money 轉帳金額 
  10.      * */  
  11.     public void transfer(String out,String in,Double money);  
  12.   
  13. }  

Service業務邏輯實現
[java] view plain copy
  1. import org.springframework.transaction.TransactionStatus;  
  2. import org.springframework.transaction.support.TransactionCallbackWithoutResult;  
  3. import org.springframework.transaction.support.TransactionTemplate;  
  4. import com.xxx.spring.chap5.dao.AccountDao;  
  5. import com.xxx.spring.chap5.service.AccountService;  
  6. /** 
  7.  * 轉帳業務接口的具體實現 
  8.  * */  
  9. public class AccountServiceImpl implements AccountService {  
  10.       
  11.     private AccountDao accountDao;  
  12.       
  13.     private TransactionTemplate transactionTemplate;  //事務管理模板  
  14.           
  15.     public TransactionTemplate getTransactionTemplate() {  
  16.         return transactionTemplate;  
  17.     }  
  18.   
  19.     public void setTransactionTemplate(TransactionTemplate transactionTemplate) {  
  20.         this.transactionTemplate = transactionTemplate;  
  21.     }  
  22.   
  23.     public AccountDao getAccountDao() {  
  24.         return accountDao;  
  25.     }  
  26.   
  27.     public void setAccountDao(AccountDao accountDao) {  
  28.         this.accountDao = accountDao;  
  29.     }  
  30.   
  31.     @Override  
  32.     public void transfer(final String out, final String in, final Double money) {  
  33.           
  34.         //使用事務模板execute中須要傳入TransactionCallback的實現類對象  
  35.         transactionTemplate.execute(new TransactionCallbackWithoutResult() {  
  36.             @Override  
  37.             protected void doInTransactionWithoutResult(TransactionStatus arg0) {  
  38.                 accountDao.outMoney(out, money);  
  39.                 accountDao.inMoney(in, money);  
  40.             }  
  41.         });  
  42.     }  
  43.   
  44. }  

持久層Dao層接口
[java] view plain copy
  1. /** 
  2.  * 轉帳的dao層接口 
  3.  * */  
  4. public interface AccountDao {  
  5.       
  6.     /** 
  7.      * @param out 轉出帳戶 
  8.      * @param money 轉帳金額 
  9.      * */  
  10.     public void outMoney(String out,Double money);  
  11.       
  12.     /** 
  13.      * @param in 轉入帳戶 
  14.      * @param money 轉帳金額 
  15.      * */  
  16.     public void inMoney(String in,Double money);  
  17.   
  18. }  

持久層Dao接口實現
[java] view plain copy
  1. import org.springframework.jdbc.core.support.JdbcDaoSupport;  
  2. import com.briup.spring.chap5.dao.AccountDao;  
  3. /** 
  4.  * 轉帳的dao層接口實現 
  5.  * Dao繼承了JdbcDaoSupport後,只要注入了鏈接池就會有模板,就能夠經過模板對數據庫進行相應的操做, 
  6.  * */  
  7. public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{  
  8.   
  9.     @Override  
  10.     public void outMoney(String out, Double money) {  
  11.         String sql = "update account set money = money - ?  where name = ?";  
  12.         this.getJdbcTemplate().update(sql, money,out);    
  13.     }  
  14.   
  15.     @Override  
  16.     public void inMoney(String in, Double money) {  
  17.         String sql = "update account set money = money + ?  where name = ?";  
  18.         this.getJdbcTemplate().update(sql, money,in);  
  19.     }  
  20.   
  21. }  

測試:
[java] view plain copy
  1. import org.junit.Test;  
  2. import org.springframework.context.ApplicationContext;  
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  4. import com.xxx.spring.chap5.service.AccountService;  
  5. /** 
  6.  * 轉帳測試類 
  7.  * */  
  8. public class SpringTransactionTest {  
  9.       
  10.     @Test  
  11.     public void test1() throws Exception {  
  12.         ApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap5/applicationContext.xml");  
  13.         AccountService accountService = ac.getBean("accountService",AccountService.class);  
  14.         accountService.transfer("張三", "李四", 200.0);  
  15.     }  
  16. }  
數據庫查詢結果
[plain] view plain copy
  1. 1   張三  800  
  2. 2   李四  1200  
  3. 3   王五  1000  

假如Service層轉帳接口出現異常
[java] view plain copy
  1. @Override  
  2.     public void transfer(final String out, final String in, final Double money) {  
  3.           
  4.         //使用事務模板TransactionCallback  
  5.         transactionTemplate.execute(new TransactionCallbackWithoutResult() {  
  6.             @Override  
  7.             protected void doInTransactionWithoutResult(TransactionStatus arg0) {  
  8.                 accountDao.outMoney(out, money);  
  9.                 int i = 1/0;  
  10.                 accountDao.inMoney(in, money);  
  11.             }  
  12.         });  
  13.     }  
會發生異常java.lang.ArithmeticException: / by zero...
錢也不會轉過去

4.2Spring中聲明式事務管理

管理創建在AOP之上的。其本質是對方法先後進行攔截,而後在目標方法開始以前建立或者加入一個事務,
在執行完目標方法以後根據執行狀況提交或者回滾事務。聲明式事務最大的優勢就是不須要經過編程的方式管理事務,
這樣就不須要在業務邏輯代碼中摻瑣事務管理的代碼,只需在配置文件中作相關的事務規則聲明
(或經過基於@Transactional註解的方式),即可以將事務規則應用到業務邏輯中。

這裏主要說了解3中實現(基於代理實現,基於AspectJ實現,基於註解實現)
4.2.1聲明式事務管理-基於代理實現
這種方式,主要是使用TransactionProxyFactoryBean代理攔截器實現,經過配置事務代理器從而實現事務管理
配置文件:applicationContext2.xml
 
[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3. <span style="white-space:pre">    </span>xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
  4.     xmlns:aop="http://www.springframework.org/schema/aop"  
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans   
  6.  http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
  7.  http://www.springframework.org/schema/aop   
  8.  http://www.springframework.org/schema/aop/spring-aop-3.2.xsd  
  9.  http://www.springframework.org/schema/context    
  10.       http://www.springframework.org/schema/context/spring-context.xsd">  
  11.       <!-- 聲明式事務管理-代理實現 -->  
  12.       <!-- 引入外部文件 -->  
  13.      <context:property-placeholder location="classpath:db.properties"/>  
  14.        
  15.      <!-- 配置c3p0的鏈接池 -->  
  16.      <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  
  17.         <property name="driverClass">  
  18.             <value>${jdbc.driver}</value>  
  19.         </property>  
  20.         <property name="jdbcUrl">  
  21.             <value>${jdbc.url}</value>  
  22.         </property>  
  23.         <property name="user">  
  24.             <value>${jdbc.username}</value>  
  25.         </property>  
  26.         <property name="password">  
  27.             <value>${jdbc.password}</value>  
  28.         </property>  
  29.      </bean>  
  30.        
  31.      <!-- 配置業務層的類 -->  
  32.      <bean id="accountService2" class="com.xxx.spring.chap5.service.impl.AccountServiceImpl2">  
  33.         <property name="accountDao" ref="accountDao2"></property>  
  34.      </bean>  
  35.      <!-- 配置dao,Dao繼承了JdbcDaoSupport後,只要注入了鏈接池就會有模板,就能夠經過模板對數據庫進行相應的操做,能夠參見源碼-->  
  36.      <bean id="accountDao2" class="com.xxx.spring.chap5.dao.impl.AccountDaoImpl2">  
  37.         <property name="dataSource" ref="dataSource"></property>  
  38.      </bean>  
  39.      <!-- 配置事務管理器 -->  
  40.      <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  41.         <property name="dataSource" ref="dataSource"></property>  
  42.      </bean>  
  43.        
  44.      <!-- 配置業務層的代理 -->  
  45.      <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">  
  46.         <!-- 配置目標類  -->  
  47.         <property name="target" ref="accountService2"></property>  
  48.         <!-- 注入事物管理器 -->  
  49.         <property name="transactionManager" ref="transactionManager"></property>  
  50.         <!-- 注入事物的相關屬性,事物的隔離級別,傳播行爲等   
  51.             key值爲方法名可使用通配符*  
  52.             value值爲  
  53.         -->  
  54.         <property name="transactionAttributes">  
  55.             <props>  
  56.                 <!-- prop的格式  
  57.                     key爲方法名,可使用*通配符號  
  58.                     value值的格式:  
  59.                         1. PROPAGATION  :事務的傳播行爲  
  60.                         2. ISOLATION    :事務隔離級別  
  61.                         3. readOnly     :只讀  
  62.                         4. -Exception   :發生那些異常回滾  
  63.                         5. +Exception   :發生那些事務不回滾  
  64.                           
  65.                         之間使用,號隔開  
  66.                  -->  
  67.                 <prop key="trans*">PROPAGATION_REQUIRED</prop>  
  68.             </props>  
  69.         </property>  
  70.      </bean>  
  71. </beans>  

Service實現改成以下:
[java] view plain copy
  1. import org.springframework.transaction.TransactionStatus;  
  2. import org.springframework.transaction.support.TransactionCallbackWithoutResult;  
  3. import org.springframework.transaction.support.TransactionTemplate;  
  4.   
  5. import com.xxx.spring.chap5.dao.AccountDao;  
  6. import com.xxx.spring.chap5.service.AccountService;  
  7.   
  8. /** 
  9.  * 轉帳業務接口的具體實現 
  10.  * */  
  11. public class AccountServiceImpl2 implements AccountService {  
  12.       
  13.     private AccountDao accountDao;  
  14.       
  15.     private TransactionTemplate transactionTemplate;  //事務管理模板    
  16.   
  17.     public TransactionTemplate getTransactionTemplate() {  
  18.         return transactionTemplate;  
  19.     }  
  20.   
  21.     public void setTransactionTemplate(TransactionTemplate transactionTemplate) {  
  22.         this.transactionTemplate = transactionTemplate;  
  23.     }  
  24.   
  25.     public AccountDao getAccountDao() {  
  26.         return accountDao;  
  27.     }  
  28.   
  29.     public void setAccountDao(AccountDao accountDao) {  
  30.         this.accountDao = accountDao;  
  31.     }  
  32.   
  33.     @Override  
  34.     public void transfer(final String out, final String in, final Double money) {  
  35.         accountDao.outMoney(out, money);  
  36.         accountDao.inMoney(in, money);  
  37.     }  
  38. }  
Dao層不變
測試類爲:
[java] view plain copy
  1. /** 
  2.      * 聲明式事務管理--代理實現 
  3.      * */  
  4.     @Test  
  5.     public void test2() throws Exception {  
  6.         ApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap5/applicationContext2.xml");  
  7.         AccountService accountService = ac.getBean("accountServiceProxy",AccountService.class);//代理對象  
  8.         accountService.transfer("張三", "李四", 200.0);  
  9.     }  
查詢結果:
[plain] view plain copy
  1. <span style="white-space:pre">    </span>1  張三  800  
  2.     2   李四  1200  
  3.     3   王五  1000  
假如Service中出現異常:
[java] view plain copy
  1. @Override  
  2.     public void transfer(final String out, final String in, final Double money) {  
  3.         accountDao.outMoney(out, money);  
  4.         int i = 1/0;  
  5.         accountDao.inMoney(in, money);  
  6.     }  
會拋出異常
java.lang.ArithmeticException: / by zero

可是錢沒有多,也沒有少,意思是本次操做失敗會,保證帳戶的安全

4.2.2聲明式事務管理-基於AspectJ實現
SpringAOP中能夠經過在xml文件中配置事務通知來對事務進行管理,這是一種更經常使用的方式

配置文件:applicationContext3.xml
[html] view plain copy
  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:tx="http://www.springframework.org/schema/tx"  
  6.     xmlns:aop="http://www.springframework.org/schema/aop"  
  7.     xsi:schemaLocation="http://www.springframework.org/schema/beans   
  8.  http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
  9.  http://www.springframework.org/schema/tx  
  10.  http://www.springframework.org/schema/tx/spring-tx.xsd  
  11.  http://www.springframework.org/schema/aop   
  12.  http://www.springframework.org/schema/aop/spring-aop-3.2.xsd  
  13.  http://www.springframework.org/schema/context    
  14.       http://www.springframework.org/schema/context/spring-context.xsd">  
  15.     <!-- 基於AspectJ的聲明式事務管理 -->  
  16.     <!-- 引入外部文件 -->  
  17.     <context:property-placeholder location="classpath:db.properties" />  
  18.   
  19.     <!-- 配置c3p0的鏈接池 -->  
  20.     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  
  21.         <property name="driverClass">  
  22.             <value>${jdbc.driver}</value>  
  23.         </property>  
  24.         <property name="jdbcUrl">  
  25.             <value>${jdbc.url}</value>  
  26.         </property>  
  27.         <property name="user">  
  28.             <value>${jdbc.username}</value>  
  29.         </property>  
  30.         <property name="password">  
  31.             <value>${jdbc.password}</value>  
  32.         </property>  
  33.     </bean>  
  34.   
  35.     <!-- 配置業務層的類 -->  
  36.     <bean id="accountService2" class="com.xxx.spring.chap5.service.impl.AccountServiceImpl2">  
  37.         <property name="accountDao" ref="accountDao2"></property>  
  38.     </bean>  
  39.     <!-- 配置dao,Dao繼承了JdbcDaoSupport後,只要注入了鏈接池就會有模板,就能夠經過模板對數據庫進行相應的操做,能夠參見源碼 -->  
  40.     <bean id="accountDao2" class="com.xxx.spring.chap5.dao.impl.AccountDaoImpl2">  
  41.         <property name="dataSource" ref="dataSource"></property>  
  42.     </bean>  
  43.     <!-- 配置事務管理器 -->  
  44.     <bean name="transactionManager"  
  45.         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  46.         <property name="dataSource" ref="dataSource"></property>  
  47.     </bean>  
  48.   
  49.     <!-- 配置事務通知 -->  
  50.     <tx:advice id="txAdvice" transaction-manager="transactionManager">  
  51.         <!-- 設置事物屬性 -->  
  52.         <tx:attributes>  
  53.             <!-- 設置各類方法的   
  54.                 propagation 爲傳播行爲   
  55.                 isolation 事務的隔離級別  
  56.                 read-only 設置之都屬性  
  57.                 rollback-for 發生生麼異常回滾  
  58.                 no-rollback-for 發生那些異常不回滾  
  59.                 -->  
  60.             <tx:method name="tran*" propagation="REQUIRED" read-only="true" />  
  61.             <tx:method name="get*" propagation="REQUIRED" read-only="true" />  
  62.             <tx:method name="find*" propagation="REQUIRED" read-only="true" />  
  63.             <tx:method name="save*" propagation="REQUIRED" read-only="false"  
  64.                 rollback-for="java.lang.Exception" />  
  65.             <tx:method name="insert*" propagation="REQUIRED" read-only="false"  
  66.                 rollback-for="java.lang.Exception" />  
  67.             <tx:method name="update*" propagation="REQUIRED" read-only="false"  
  68.                 rollback-for="java.lang.Exception" />  
  69.             <tx:method name="delete*" propagation="REQUIRED" read-only="false"  
  70.                 rollback-for="java.lang.Exception" />  
  71.             <tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception" />  
  72.         </tx:attributes>  
  73.     </tx:advice>  
  74.   
  75.     <!-- 配置AOP -->  
  76.     <aop:config>  
  77.         <!-- 配置切入點,表示切入點爲類AccountServiceImpl2下的全部方法 -->  
  78.         <aop:pointcut  
  79.             expression="execution(* com.xxx.spring.chap5.service.impl.AccountServiceImpl2.*(..))"  
  80.             id="pointcut" />  
  81.         <!-- 配置切面,表示AccountServiceImpl2下的全部方法都使用txAdivice加強 -->  
  82.         <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />  
  83.     </aop:config>  
  84. </beans>  
Service實現
[java] view plain copy
  1. import org.springframework.transaction.annotation.Propagation;  
  2. import org.springframework.transaction.annotation.Transactional;  
  3. import org.springframework.transaction.support.TransactionTemplate;  
  4. import com.xxx.spring.chap5.dao.AccountDao;  
  5. import com.xxx.spring.chap5.service.AccountService;  
  6.   
  7. /** 
  8.  * 轉帳業務接口的具體實現 
  9.  *  
  10.  * */  
  11. public class AccountServiceImpl2 implements AccountService {  
  12.       
  13.     private AccountDao accountDao;  
  14.   
  15.     private TransactionTemplate transactionTemplate;  //事務管理模板  
  16.           
  17.     public TransactionTemplate getTransactionTemplate() {  
  18.         return transactionTemplate;  
  19.     }  
  20.   
  21.     public void setTransactionTemplate(TransactionTemplate transactionTemplate) {  
  22.         this.transactionTemplate = transactionTemplate;  
  23.     }  
  24.   
  25.     public AccountDao getAccountDao() {  
  26.         return accountDao;  
  27.     }  
  28.     public void setAccountDao(AccountDao accountDao) {  
  29.         this.accountDao = accountDao;  
  30.     }  
  31.     @Override  
  32.     public void transfer(final String out, final String in, final Double money) {  
  33.         accountDao.outMoney(out, money);  
  34.         accountDao.inMoney(in, money);  
  35.     }  
  36.   
  37. }  
測試:
[java] view plain copy
  1. /** 
  2.      * 聲明式事務管理-基於AspectJ實現 
  3.      * */  
  4.     @Test  
  5.     public void test3() throws Exception {  
  6.         ApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap5/applicationContext3.xml");  
  7.         AccountService accountService = ac.getBean("accountService2",AccountService.class);  
  8.         accountService.transfer("張三", "李四", 200.0);  
  9.     }  
查詢結果:
[plain] view plain copy
  1. 1   張三  800  
  2. 2   李四  1200  
  3. 3   王五  1000  

4.2.3聲明式事務管理-基於註解實現
這種也是一種比較常見的使用,主要在xml文件中開始事務註解後,在須要使用事務的業務中添加@Transactionl註解
能夠參見:http://www.cnblogs.com/younggun/archive/2013/07/16/3193800.html

配置文件:applicationContext4.xml
[html] view plain copy
  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:tx="http://www.springframework.org/schema/tx"  
  6.     xmlns:aop="http://www.springframework.org/schema/aop"  
  7.     xsi:schemaLocation="http://www.springframework.org/schema/beans   
  8.  http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
  9.  http://www.springframework.org/schema/aop   
  10.  http://www.springframework.org/schema/aop/spring-aop-3.2.xsd  
  11.   http://www.springframework.org/schema/tx  
  12.  http://www.springframework.org/schema/tx/spring-tx.xsd  
  13.  http://www.springframework.org/schema/context    
  14.       http://www.springframework.org/schema/context/spring-context.xsd">  
  15.     <!-- 基於註解式事務管理 -->  
  16.     <!-- 引入外部文件 -->  
  17.     <context:property-placeholder location="classpath:db.properties" />  
  18.   
  19.     <!-- 配置c3p0的鏈接池 -->  
  20.     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">  
  21.         <property name="driverClass">  
  22.             <value>${jdbc.driver}</value>  
  23.         </property>  
  24.         <property name="jdbcUrl">  
  25.             <value>${jdbc.url}</value>  
  26.         </property>  
  27.         <property name="user">  
  28.             <value>${jdbc.username}</value>  
  29.         </property>  
  30.         <property name="password">  
  31.             <value>${jdbc.password}</value>  
  32.         </property>  
  33.     </bean>  
  34.   
  35.     <!-- 配置業務層的類 -->  
  36.     <bean id="accountService2" class="com.xxx.spring.chap5.service.impl.AccountServiceImpl2">  
  37.         <property name="accountDao" ref="accountDao2"></property>  
  38.     </bean>  
  39.     <!-- 配置dao,Dao繼承了JdbcDaoSupport後,只要注入了鏈接池就會有模板,就能夠經過模板對數據庫進行相應的操做,能夠參見源碼 -->  
  40.     <bean id="accountDao2" class="com.xxx.spring.chap5.dao.impl.AccountDaoImpl2">  
  41.         <property name="dataSource" ref="dataSource"></property>  
  42.     </bean>  
  43.     <!-- 配置事務管理器 -->  
  44.     <bean name="transactionManager"  
  45.         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  46.         <property name="dataSource" ref="dataSource"></property>  
  47.     </bean>  
  48.   
  49.     <!-- 註解事務管理器配置 -->  
  50.     <tx:annotation-driven transaction-manager="transactionManager"/>  
  51. </beans>  
Sservice業務層實現:
[java] view plain copy
  1. import org.springframework.transaction.annotation.Propagation;  
  2. import org.springframework.transaction.annotation.Transactional;  
  3. import org.springframework.transaction.support.TransactionTemplate;  
  4. import com.xxx.spring.chap5.dao.AccountDao;  
  5. import com.xxx.spring.chap5.service.AccountService;  
  6. /** 
  7.  * 轉帳業務接口的具體實現 
  8.  *  
  9.  * @Transactional中註解的屬性: 
  10.  * propagation:事務的傳播行爲 
  11.  * isolation:事務的隔離級別 
  12.  * readOnly:是否只讀 
  13.  * rollbackFor:發生那些異常回滾 
  14.  * noRollbackFor:發生那些異常不回滾,這些默承認以不寫使用@Transactional就行 
  15.  * */  
  16. @Transactional(propagation=Propagation.REQUIRED,readOnly=true,rollbackFor={RuntimeException.class, Exception.class})  
  17. public class AccountServiceImpl2 implements AccountService {  
  18.       
  19.     private AccountDao accountDao;  
  20.     public AccountDao getAccountDao() {  
  21.         return accountDao;  
  22.     }  
  23.   
  24.     public void setAccountDao(AccountDao accountDao) {  
  25.         this.accountDao = accountDao;  
  26.     }  
  27.     @Override  
  28.     public void transfer(final String out, final String in, final Double money) {  
  29.         accountDao.outMoney(out, money);  
  30.         accountDao.inMoney(in, money);  
  31.     }  
  32.   
  33. }  

測試:
[java] view plain copy
  1. /** 
  2.      * 4聲明式事務管理-基於註解的實現 
  3.      * */  
  4.     @Test  
  5.     public void test4() throws Exception {  
  6.         ApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap5/applicationContext4.xml");  
  7.         AccountService accountService = ac.getBean("accountService2",AccountService.class);  
  8.         accountService.transfer("張三", "李四", 200.0);  
  9.     }  
查詢結果:
[plain] view plain copy
  1. 1   張三  800  
  2. 2   李四  1200  
  3. 3   王五  1000  
相關文章
相關標籤/搜索