Spring中对事务的声明式管理

拿一个XML举例

  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:aop="http://www.springframework.org/schema/aop"  
  5.        xmlns:tx="http://www.springframework.org/schema/tx"  
  6.        xsi:schemaLocation="  
  7.        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd  
  8.        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd  
  9.        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">  
  10.   
  11.   
  12.   事务管理目标Service  
  13.   <bean id="fooService" class="x.y.service.DefaultFooService"/>  
  14.     
  15.   切面配置,配置了切入点是执行FooService下的所有方法 和 切入点调用的通知器为txAdvice  
  16.   <aop:config>  
  17.     <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>  
  18.     <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>  
  19.   </aop:config>  
  20.     
  21.   该通知器的具体配置,所使用的事务管理器,所配置的事务规则  
  22.   <tx:advice id="txAdvice" transaction-manager="txManager">  
  23.     <!-- the transactional semantics... -->  
  24.       
  25.     <tx:attributes>  
  26.       <!-- all methods starting with 'get' are read-only -->  
  27.         
  28.       <tx:method name="get*" read-only="true"/>  
  29.       <!-- other methods use the default transaction settings (see below) -->  
  30.         
  31.       <tx:method name="*"/>  
  32.     </tx:attributes>  
  33.   </tx:advice>  
  34.   
  35.   所选用的事务管理器,和作为启动参数塞入的dataSource  
  36.   <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  37.     <property name="dataSource" ref="dataSource"/>  
  38.   </bean>  
  39.   
  40.   
  41.   连接数据库的dataSource  
  42.   <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
  43.     <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>  
  44.     <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>  
  45.     <property name="username" value="scott"/>  
  46.     <property name="password" value="tiger"/>  
  47.   </bean>  
  48.     
  49. </beans>  

Spring中对事务管理的底层实现

以上的方法,选用了Spring本身自带的JDBC的事务控制器做处理。

相关代码集中在DataSourceTransactionManager中

比如,事务的取得并且将取得的事务捆绑进当前线程中

  1. @Override  
  2.     protected Object doGetTransaction() {  
  3.         DataSourceTransactionObject txObject = new DataSourceTransactionObject();  
  4.         txObject.setSavepointAllowed(isNestedTransactionAllowed());  
  5.         ConnectionHolder conHolder =  
  6.             (ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);  
  7.         txObject.setConnectionHolder(conHolder, false);  
  8.         return txObject;  
  9.     }  

在比如事务的开始,

  1. /** 
  2.      * This implementation sets the isolation level but ignores the timeout. 
  3.      */  
  4.     @Override  
  5.     protected void doBegin(Object transaction, TransactionDefinition definition) {  
  6.         DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;  
  7.         Connection con = null;  
  8.   
  9.         try {  
  10.             if (txObject.getConnectionHolder() == null ||  
  11.                     txObject.getConnectionHolder().isSynchronizedWithTransaction()) {  
  12.                 Connection newCon = this.dataSource.getConnection();  
  13.                 if (logger.isDebugEnabled()) {  
  14.                     logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");  
  15.                 }  
  16.                 txObject.setConnectionHolder(new ConnectionHolder(newCon), true);  
  17.             }  
  18.   
  19.             txObject.getConnectionHolder().setSynchronizedWithTransaction(true);  
  20.             con = txObject.getConnectionHolder().getConnection();  
  21.   
  22.             Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);  
  23.             txObject.setPreviousIsolationLevel(previousIsolationLevel);  
  24.   
  25.             // Switch to manual commit if necessary. This is very expensive in some JDBC drivers,  
  26.             // so we don't want to do it unnecessarily (for example if we've explicitly  
  27.             // configured the connection pool to set it already).  
  28.             if (con.getAutoCommit()) {  
  29.                 txObject.setMustRestoreAutoCommit(true);  
  30.                 if (logger.isDebugEnabled()) {  
  31.                     logger.debug("Switching JDBC Connection [" + con + "] to manual commit");  
  32.                 }  
  33.                 con.setAutoCommit(false);  
  34.             }  
  35.             txObject.getConnectionHolder().setTransactionActive(true);  
  36.   
  37.             int timeout = determineTimeout(definition);  
  38.             if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {  
  39.                 txObject.getConnectionHolder().setTimeoutInSeconds(timeout);  
  40.             }  
  41.   
  42.             // Bind the session holder to the thread.  
  43.             if (txObject.isNewConnectionHolder()) {  
  44.                 TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());  
  45.             }  
  46.         }  
  47.   
  48.         catch (Exception ex) {  
  49.             DataSourceUtils.releaseConnection(con, this.dataSource);  
  50.             throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);  
  51.         }  
  52.     }