Spring2.0 事务处理

[color=red][/color]http://doc.javanb.com/spring-framework-reference-zh-2-0-5/ch09s05.html

TransactionProxyFactoryBean在哪儿?
Spring2.0及以后的版本中声明式事务的配置与之前的版本有相当大的不同。主要差异在于不再需要配置TransactionProxyFactoryBean了。

Spring2.0之前的旧版本风格的配置仍然是有效的;你可以简单地认为新的<tx:tags/>替你定义了TransactionProxyFactoryBean。

回滚规则的概念比较重要:它使我们能够指定什么样的异常(和throwable)将导致自动回滚。我们在配置文件中声明式地指定,无须在Java代码中。同时,我们仍旧可以通过调用 TransactionStatus 的 setRollbackOnly() 方法编程式地回滚当前事务。通常,我们定义一条规则,声明 MyApplicationException 必须总是导致事务回滚。这种方式带来了显著的好处,它使你的业务对象不必依赖于事务设施。典型的例子是你不必在代码中导入Spring API,事务等。

对EJB来说,默认的行为是EJB容器在遇到 系统异常(通常指运行时异常)时自动回滚当前事务。EJB CMT遇到 应用异常(例如,除了 java.rmi.RemoteException 外别的checked exception)时并不会自动回滚。默认式Spring处理声明式事务管理的规则遵守EJB习惯(只在遇到unchecked exceptions时自动回滚),但通常定制这条规则会更有用。

9.5.2. 第一个例子
请看下面的接口和它的实现。这个例子的意图是介绍概念,使用 Foo 和 Bar 这样的名字只是为了让你关注于事务的用法,而不是领域模型。

package x.y.service;

public interface FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);

}



<!-- 上述接口的一个实现 -->
           

package x.y.service;

public class DefaultFooService implements FooService {

    public Foo getFoo(String fooName) {
        throw new UnsupportedOperationException();
    }

    public Foo getFoo(String fooName, String barName) {
        throw new UnsupportedOperationException();
    }

    public void insertFoo(Foo foo) {
        throw new UnsupportedOperationException();
    }

    public void updateFoo(Foo foo) {
        throw new UnsupportedOperationException();
    }
}


(对该例的目的来说,上例中实现类(DefaultFooService)的每个方法在其方法体中抛出 UnsupportedOperationException 的做法是恰当的,我们可以看到,事务被创建出来,响应 UnsupportedOperationException 的抛出,然后回滚。)

我们假定,FooService的前两个方法(getFoo(String)和getFoo(String, String))必须执行在只读事务上下文中,其余方法(insertFoo(Foo)和updateFoo(Foo))必须执行在读写事务上下文中。

使用XML方式元数据的声明式配置的话,你得这么写(不要想着一次全部理解,所有内容会在后面的章节详细讨论):

<!-- 'context.xml'文件的内容如下: -->
            
<?xml version="1.0" encoding="UTF-8"?>
<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-2.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

  <!-- 这是我们将要配置并使它具有事务性的Service对象 -->
  
  <bean id="fooService" class="x.y.service.DefaultFooService"/>

  
  <!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> bean below) -->
  
  <tx:advice id="txAdvice" transaction-manager="txManager">
    <!-- the transactional semantics... -->
    
    <tx:attributes>
      <!-- all methods starting with 'get' are read-only -->
      
      <tx:method name="get*" read-only="true"/>
      <!-- other methods use the default transaction settings (see below) -->
      
      <tx:method name="*"/>
    </tx:attributes>
  </tx:advice>

  <!-- ensure that the above transactional advice runs for any execution
      of an operation defined by the FooService interface -->
      
  <aop:config>
    <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
  </aop:config>

  <!-- don't forget the DataSource -->
  
  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
    <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
    <property name="username" value="scott"/>
    <property name="password" value="tiger"/>
  </bean>

  
  <!-- similarly, don't forget the (particular) PlatformTransactionManager -->
  
  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
  </bean>

  <!-- other <bean/> definitions here -->
  
</beans>


我们来分析一下上面的配置。我们要把一个服务对象('fooService' bean)做成事务性的。我们想施加的事务语义封装在<tx:advice/>定义中。<tx:advice/> “把所有以 'get' 开头的方法看做执行在只读事务上下文中,其余的方法执行在默认语义的事务上下文中”。 其中的 'transaction-manager' 属性被设置为一个指向 PlatformTransactionManager bean的名字(这里指 'txManager'),该bean将实际上实施事务管理。

提示
事实上,如果 PlatformTransactionManager bean的名字是 'transactionManager' 的话,你的事务通知(<tx:advice/>)中的 'transaction-manager' 属性可以忽略。否则你则需要像上例那样明确指定。

配置中最后一段是 <aop:config/> 的定义,它确保由 'txAdvice' bean定义的事务通知在应用中合适的点被执行。首先我们定义了 一个切面,它匹配 FooService 接口定义的所有操作,我们把该切面叫做 'fooServiceOperation'。然后我们用一个通知器(advisor)把这个切面与 'txAdvice' 绑定在一起,表示当 'fooServiceOperation' 执行时,'txAdvice' 定义的通知逻辑将被执行。

一个普遍性的需求是让整个服务层成为事务性的。满足该需求的最好方式是让切面表达式匹配服务层的所有操作方法。例如:

<aop:config>
    <aop:pointcut id="fooServiceMethods" expression="execution(* x.y.service.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods"/>
  </aop:config>


现在,既然我们已经分析了整个配置,你可能会问了,“好吧,但是所有这些配置做了什么?”。

上面的配置将为由 'fooService' 定义的bean创建一个代理对象,这个代理对象被装配了事务通知,所以当它的相应方法被调用时,一个事务将被启动、挂起、被标记为只读,或者其它(根据该方法所配置的事务语义)。

我们来看看下面的例子,测试一下上面的配置。

public final class Boot {

    public static void main(final String[] args) throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("context.xml", Boot.class);
        FooService fooService = (FooService) ctx.getBean("fooService");
        fooService.insertFoo (new Foo());
    }
}


运行上面程序的输出结果看起来像这样(注意为了清楚起见,Log4J的消息和从 DefaultFooService 的 insertFoo(..) 方法抛出的 UnsupportedOperationException 异常堆栈信息被省略了)。




附件 自己练习时候写的 applicationContext.xml 配置

你可能感兴趣的:(spring,xml,bean,ejb,配置管理)