`

Spring 事务 (二) Spring 声明式事务 配置

阅读更多

Spring 事务 (二) Spring 声明式事务 配置

 

2.  Spring 声明式事务 配置

 

     由Spring 事务 (一)知道,Spring事务基本概念中,最重要的是

     PlatformTransactionManager,它的

     TransactionStatus getTransaction(TransactionDefinition definition)

     方法根据一个TransactionDefinition生成TransactionStatus.

     这样可知,配置事务,首先需要配置一个PlatformTransactionManager信息,

     然后需要配置 TransactionDefinition信息.而TransactionStatus是返回的值,

     根据前面两个配置由TransactionStatus对象获取相应的配置信息.

     

     所以配置时,主要配置PlatformTransactionManager,TransactionDefinition.

     

     Spring的事务功能由事务代理完成.

     一般的流程是:

     先编写业务接口,

     然后编写一个业务接口的实现类,并配置为bean(targetBean),

     再配置一个TransactionProxyFactoryBean,得到一个代理bean(代理targetBean),

     然后客户端代码中,通过代理bean的id来调用getBean方法,得到TransactionProxyFactoryBean配置的bean.

     

     配置这个代理bean需要传入一个事务管理器(PlatformTransactionManager),一个目标bean(targetBean),

     并指定事务代理的事务属性.

     

     上述配置TransactionProxyFactoryBean的方式为显示的,即配置一个targetBean,和一个有事务行为的代理bean,

     实际上配置了两个bean,而原来的targetBean是不直接使用的,假如代码中不小心使用了targetBean,则会产生问题.

     

     因此Spring还提供了一种基于tx命名空间的方式来配置事务代理bean,这种配置类似于AOP配置,只配置一个bean,

     当根据bean id使用getBean()获取bean实例时,Spring容器自动提供事务代理bean的实例.

     

     http://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/section5.html

     上面链接中,还讨论了使用拦截器实现的事务(非事务代理bean方式),供参考.

     

   

2.1  PlatformTransactionManager配置

 

     PlatformTransactionManager配置,根据不同数据源的使用,以及是局部事务还是全局事务 来分类,

     主要有下面几种配置方式:

     

2.1.1 数据源使用JDBC数据源的局部事务,使用DataSourceTransactionManager类

 

     

<!-- 数据源使用JDBC数据源的局部事务,使用DataSourceTransactionManager类 -->
     <!-- DataSource配置,可配置为c3p0连接池等,这里省略 -->
     <bean id="dataSource" ...>...</bean>
     <bean id="transactionManager" 
           class="org.springframework.jdbc.datasouce.DataSouceTransactionManager">
       <!-- 配置DataSourceTransactionManager时,需要依赖注入DataSource的引用 -->
       <property name="dataSource" ref="dataSource"/>      
     </bean>

 

 

2.1.2  采用全局事务的特定实现

    

     

<!-- 采用全局事务的特定实现 -->
     <bean id="transactionManager" 
           class="org.springframework.transaction.jta.JtaTransactionManager" />

 
 

     

     上面配置,无需指定datasource. 全局事务有JTA实现(比如有的容器weblogic等实现JTA,

     也有专门的开源框架实现JTA,如JOTM)     

 

2.1.3 使用Hibernate的配置

 

     

<!-- 使用Hibernate的配置 -->
     <!-- DataSource配置,可配置为c3p0连接池等,这里省略 -->
     <bean id="dataSource" ...>...</bean>
     <!-- Hibernate的SessionFactory配置,这里省略 --> 
     <bean id="sessionFactory" ...>...</bean>
     <bean id="transactionManager"
           <!-- 针对Hibernate的特定实现类 --> 
           class="org.springframework.orm.hibernate3.HibernateTransactionManager">
       <!-- 配置Hibernate时,需要依赖注入SessionFactory的引用 -->
       <property name="sessionFactory" ref="sessionFactory"/>      
     </bean>

 

     

3 配置 TransactionProxyFactoryBean

 

3.1 配置一个targetBean(业务逻辑bean),和一个有事务行为的代理bean

 

     

<!-- 数据源使用JDBC数据源的局部事务,使用DataSourceTransactionManager类 -->
     <!-- DataSource配置,可配置为c3p0连接池等,这里省略 -->
     <bean id="dataSource" ...>...</bean>
     <bean id="transactionManager" 
           class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <!-- 配置DataSourceTransactionManager时,需要依赖注入DataSource的引用 -->
       <property name="dataSource" ref="dataSource"/>      
     </bean>
     
     <!-- 一个业务逻辑bean -->
     <bean id="newsDao" class="xxx.xxx.NewsDao" >
       <property name="ds" ref="dataSource" />
     </bean>
     
     <!-- 为业务逻辑bean配置事务代理 -->
     <bean id="newsDaoTran" class="org.springframework.transaction.intereptor.TransactionProxyFactoryBean">
       <!-- 注入事务管理器 -->
       <property name="transactionManager" ref="transactionManager" />
       <!-- 指定被代理的目标bean -->
       <property name="target" ref="newDao" />
       <!-- 指定事务属性 -->
       <property name="transactionAttributes">
         <props>
           <prop key="*">PROPAGATION_REQUIRED</prop>
         </props>
       </property>
     </bean>

 

     

     上面transactionAttributes标示注入的是一个properties类型的属性.

     key表示方面名称,可以使用通配符,

     value表示事务规则:

     指定事务属性的取值有较复杂的规则,具体的书写规则如下:

     

     传播行为 [,隔离级别] [,只读属性] [,超时属性] [不影响提交的异常] [,导致回滚的异常]

     

     只有传播行为是必须指定的,其他的可以省略(取默认值)

     

      传播行为是唯一必须设置的属性,其他都可以忽略,Spring为我们提供了合理的默认值。

      传播行为的取值必须以“PROPAGATION_”开头,

        具体包括:

        PROPAGATION_MANDATORY、

        PROPAGATION_NESTED、

        PROPAGATION_NEVER、

        PROPAGATION_NOT_SUPPORTED、

        PROPAGATION_REQUIRED、

        PROPAGATION_REQUIRES_NEW、

        PROPAGATION_SUPPORTS,共七种取值。

      隔离级别的取值必须以“ISOLATION_”开头,

        具体包括:

        ISOLATION_DEFAULT、

        ISOLATION_READ_COMMITTED、

        ISOLATION_READ_UNCOMMITTED、

        ISOLATION_REPEATABLE_READ、

        ISOLATION_SERIALIZABLE,共五种取值。

      如果事务是只读的,那么我们可以指定只读属性,

        使用“readOnly”指定。否则我们不需要设置该属性。

      超时属性的取值必须以“TIMEOUT_”开头,

        后面跟一个int类型的值,表示超时时间,单位是秒。

      不影响提交的异常是指,即使事务中抛出了这些类型的异常,

        事务任然正常提交。必须在每一个异常的名字前面加上“+”。

        异常的名字可以是类名的一部分。比如“+RuntimeException”、“+tion”等等。

      导致回滚的异常是指,当事务中抛出这些类型的异常时,事务将回滚。

        必须在每一个异常的名字前面加上“-”。异常的名字可以是类名的全部或者部分,

        比如“-RuntimeException”、“-tion”等等。

        

      以下是两个示例:

      

<property name="*Service">
          PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED,TIMEOUT_20,
          +AbcException,+DefException,-HijException
      </property>

 

 

      以上表达式表示,针对所有方法名以 Service 结尾的方法,

      使用 PROPAGATION_REQUIRED 事务传播行为,

      事务的隔离级别是 ISOLATION_READ_COMMITTED,

      超时时间为20秒,

      当事务抛出 AbcException 或者 DefException 类型的异常,则仍然提交,

      当抛出 HijException 类型的异常时必须回滚事务。

      这里没有指定"readOnly",表示事务不是只读的。

      

      

<property name="test">PROPAGATION_REQUIRED,readOnly</property>

 

 

      以上表达式表示,针对所有方法名为 test 的方法,

      使用 PROPAGATION_REQUIRED 事务传播行为,

      并且该事务是只读的。

      除此之外,其他的属性均使用默认值。

      比如,隔离级别和超时时间使用底层事务性资源的默认值,

      并且当发生未检查异常,则回滚事务,

      发生已检查异常则仍提交事务。

      

      参考:

      http://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/section5.html

      

3.2  基于tx命名空间的方式来配置事务代理bean

      这种配置类似于AOP配置,只配置一个bean,

      当根据bean id使用getBean()获取bean实例时,Spring容器自动提供事务代理bean的实例.

      

      

<?xml version="1.0" encoding="UTF-8"?>
      <!-- 需要使用这样的beans头,指定tx,aop的schema -->  
      <beans xmlns="http://www.springframework.org/schema/beans"  
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
              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-3.0.xsd
                  http://www.springframework.org/schema/aop 
                  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
                  http://www.springframework.org/schema/tx 
                  http://www.springframework.org/schema/tx/spring-tx-3.0.xsd" 
      > 
      
         <!-- 数据源使用JDBC数据源的局部事务,使用DataSourceTransactionManager类 -->
         <!-- DataSource配置,可配置为c3p0连接池等,这里省略 -->
         <bean id="dataSource" ...>...</bean>
         <bean id="transactionManager" 
               class="org.springframework.jdbc.datasouce.DataSouceTransactionManager">
           <!-- 配置DataSourceTransactionManager时,需要依赖注入DataSource的引用 -->
           <property name="dataSource" ref="dataSource"/>      
         </bean>
         
         <!-- 一个业务逻辑bean -->
         <bean id="newsDao" class="xxx.xxx.NewsDao" >
           <property name="ds" ref="newsDao" />
         </bean>
         
         <!-- 
              配置增强处理的bean(相当于切面类),也是Spring自动生成普通
              业务逻辑bean(targetBean)的代理Bean.里面的tx:method配置每个方法的事务属性,
              name配置方法名,可使用通配符.
         -->
         <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <!-- 配置详细的事务语义 -->
            <tx:attributes>
              <!-- 表示get开头的方法是只读的 -->
              <tx:method name="get*" read-only="true" />
              <!-- 其他方法使用默认的事务设置,事务传播方式也可以默认么? -->
              <tx:method name="*" />
            </tx:attributes>
         </tx:advice>
         
         <!-- AOP元素配置 -->
         <aop:config>
           <!-- 配置一个切入点 xxx.xxx包下面所有已Imp1结尾的类的所有方法-->
           <aop:pointcut id="myPoint" 
                         expression="execution(* xxx.xxx.*Imp1.*(..))" />
           <!-- 配置 (事务代理)切入点(aop:pointcut) 和 切面类(tx:advice),将二者关联起来  -->
           <aop:advisor advice-ref="txAdvice" pointcut-ref="myPoint" />
         </aop:config>
      </beans>

 

      

      注:

        aop:config中 aop:pointcut配置切入点,表名哪些方法将会被事务代理增强.

        tx:advice 相当于配置一个切面类,并标明对符合条件的方法采用何种事务.

        aop:config中aop:advisor将上述二者关联起来

        

        <tx:attributes>的tx:method的

         name属性是必须的,可以使用通配符,表示与改事务语义管理的方法名.

         另外,还有属性:

         propagation,isolation,timeout,read-only,rollbak-for,no-rallback-for.(P684)

        

      附件中 classes12.jar是oracle的驱动包.

          

     

         

     

     

     

 

    

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics