`
pingwei000
  • 浏览: 60878 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

SSH框架事务

阅读更多
如果你用的是myeclipse的话,直接就有了集成的方案,
声明式事务,就自己去下个spring文档就有了

9.5. 声明式事务管理
大多数Spring用户选择声明式事务管理。这是对应用代码影响最小的选择,因此也最符合 非侵入式 轻量级容器的理念。

Spring的声明式事务管理是通过Spring AOP实现的,因为事务方面的代码与Spring绑定并以一种样板式风格使用,不过尽管如此,你一般并不需要理解AOP概念就可以有效地使用Spirng的声明式事务管理。

从考虑EJB CMT和Spring声明式事务管理的相似以及不同之处出发是很有益的。它们的基本方法是相似的:都可以指定事务管理到单独的方法;如果需要可以在事务上下文调用 setRollbackOnly() 方法。不同之处在于:

不像EJB CMT绑定在JTA上,Spring声明式事务管理可以在任何环境下使用。只需更改配置文件,它就可以和JDBC、JDO、Hibernate或其他的事务机制一起工作。

Spring的声明式事务管理可以被应用到任何类(以及那个类的实例)上,不仅仅是像EJB那样的特殊类。

Spring提供了声明式的回滚规则:EJB没有对应的特性,我们将在下面讨论。回滚可以声明式的控制,不仅仅是编程式的。

Spring允许你通过AOP定制事务行为。例如,如果需要,你可以在事务回滚中插入定制的行为。你也可以增加任意的通知,就象事务通知一样。使用EJB CMT,除了使用setRollbackOnly(),你没有办法能够影响容器的事务管理。

Spring不提供高端应用服务器提供的跨越远程调用的事务上下文传播。如果你需要这些特性,我们推荐你使用EJB。然而,不要轻易使用这些特性。通常我们并不希望事务跨越远程调用。

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.1. 理解Spring的声明式事务管理实现
本节的目的是消除与使用声明式事务管理有关的神秘性。简单点儿总是好的,这份参考文档只是告诉你给你的类加上@Transactional注解,在配置文件中添加('<tx:annotation-driven/>')行,然后期望你理解整个过程是怎么工作的。此节讲述Spring的声明式事务管理内部的工作机制,以帮助你在面对事务相关的问题时不至于误入迷途,回朔到上游平静的水域。

提示
阅读Spring源码是理解清楚Spring事务支持的一个好方法。Spring的Javadoc提供的信息丰富而完整。我们建议你在开发自己的Spring应用时把日志级别设为'DEBUG'级,这样你能更清楚地看到幕后发生的事。

在理解Spring的声明式事务管理方面最重要的概念是:Spring的事务管理是通过AOP代理实现的。其中的事务通知由元数据(目前基于XML或注解)驱动。代理对象与事务元数据结合产生了一个AOP代理,它使用一个PlatformTransactionManager实现品配合TransactionInterceptor,在方法调用前后实施事务。

注意
尽管使用Spring声明式事务管理不需要AOP(尤其是Spring AOP)的知识,但了解这些是很有帮助的。你可以在 第 6 章使用Spring进行面向切面编程(AOP) 章找到关于Spring AOP的全部内容。

概念上来说,在事务代理上调用方法的工作过程看起来像这样:


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:pointcut/> 元素定义是AspectJ的切面表示法,可参考Spring 2.0 第 6 章使用Spring进行面向切面编程(AOP)章获得更详细的内容。

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

<aop:config>
    <aop:pointcut id="fooServiceMethods" expression="execution(* x.y.service.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods"/>
  </aop:config>
(这个例子中假定你所有的服务接口定义在 'x.y.service' 包中。你同样可以参考 第 6 章使用Spring进行面向切面编程(AOP) 章获得更详细内容。)

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

上面的配置将为由 '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 异常堆栈信息被省略了)。

<!-- Spring容器开始启动... -->

[AspectJInvocationContextExposingAdvisorAutoProxyCreator] - Creating implicit proxy
        for bean 'fooService' with 0 common interceptors and 1 specific interceptors
    <!-- the DefaultFooService is actually proxied -->
  
[JdkDynamicAopProxy] - Creating JDK dynamic proxy for [x.y.service.DefaultFooService]

    <!-- ... the insertFoo(..) method is now being invoked on the proxy -->
  

[TransactionInterceptor] - Getting transaction for x.y.service.FooService.insertFoo
    <!-- the transactional advice kicks in here... -->
  
[DataSourceTransactionManager] - Creating new transaction with name [x.y.service.FooService.insertFoo]
[DataSourceTransactionManager] - Acquired Connection
        [org.apache.commons.dbcp.PoolableConnection@a53de4] for JDBC transaction

    <!-- the insertFoo(..) method from DefaultFooService throws an exception... -->
  
[RuleBasedTransactionAttribute] - Applying rules to determine whether transaction should
        rollback on java.lang.UnsupportedOperationException
[TransactionInterceptor] - Invoking rollback for transaction on x.y.service.FooService.insertFoo
        due to throwable [java.lang.UnsupportedOperationException]

   <!-- and the transaction is rolled back (by default, RuntimeException instances cause rollback) -->
 
[DataSourceTransactionManager] - Rolling back JDBC transaction on Connection
        [org.apache.commons.dbcp.PoolableConnection@a53de4]
[DataSourceTransactionManager] - Releasing JDBC Connection after transaction
[DataSourceUtils] - Returning JDBC Connection to DataSource

Exception in thread "main" java.lang.UnsupportedOperationException
at x.y.service.DefaultFooService.insertFoo(DefaultFooService.java:14)
   <!-- AOP infrastructure stack trace elements removed for clarity -->
 
at $Proxy0.insertFoo(Unknown Source)
at Boot.main(Boot.java:11)
9.5.3. 回滚
在前面的章节里,概述了如何在你的应用里为类特别是服务层的类指定事务性的基本方法。这一章将描述在一个简单的声明式配置中如何你才能控制事务的回滚。

一个容易的(和被推荐的)方法是在Spring框架的事务架构里指出当context的事务里的代码抛出 Exception 时事务进行回滚。Spring框架的事务基础架构代码将从调用的堆栈里捕获到任何未处理的 Exception,并将标识事务将回滚。

然而,请注意Spring框架的事务基础架构代码将默认地 只 在抛出运行时和unchecked exceptions时才标识事务回滚。 也就是说,当抛出一个 RuntimeException 或其子类例的实例时。(Errors 也一样 - 默认地 - 标识事务回滚。)从事务方法中抛出的Checked exceptions将 不 被标识进行事务回滚。

就是这些默认的设置;严格规定了哪些 Exception 类型将被标识进行事务回滚。下面的XML配置片断里示范了如何配置一个checked,应用程序指定的 Exception 类型来标识事务回滚。

<tx:advice id="txAdvice" transaction-manager="txManager">
  <tx:attributes>
<tx:method name="get*" read-only="false" rollback-for="NoProductInStockException"/>
<tx:method name="*"/>
  </tx:attributes>
</tx:advice>
第二方法是在Spring框架的事务架构里通过 编程式方式指出一个事务将被回滚。虽然这个非常简单,但是这个方法对于Spring框架的事务架构来说,在你的代码是高入侵的和紧藕合的下面的代码片断里示范了Spring框架管理事务的编程式回滚:

public void resolvePosition() {
    try {
        // some business logic...
    } catch (NoProductInStockException ex) {
        // trigger rollback programmatically
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}
强烈推荐你尽可能地使用声明式事务回滚方法。编程式方法的回滚对你来说是可见,如果你需要它你就可以使用,但是使用它就直接违反了在你的应用中使用一个纯基于POJO的模型。

9.5.4. 为不同的bean配置不同的事务语义
现在我们考虑一下这样的场景,你有许多服务对象,而且想为不同组的对象设置 完全不同的事务语义。在Spring中,你可以通过定义各自特定的 <aop:advisor/> 元素,每个advisor采用不同的 'pointcut' 和 'advice-ref' 属性,来达到目的。

借助于一个例子,我们假定你所有的服务层类定义在以 'x.y.service' 为根的包内。为了让service包(或子包)下所有名字以 'Service' 结尾的类的对象拥有默认的事务语义,你可以配置如下:

<?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">

<aop:config>

    <aop:pointcut id="serviceOperation" expression="execution(* x.y.service..*Service.*(..))"/>

        <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/>

</aop:config>

<!-- these two beans will be transactional... -->

<bean id="fooService" class="x.y.service.DefaultFooService"/>
<bean id="barService" class="x.y.service.extras.SimpleBarService"/>

<!-- ...and these two beans won't -->

    <bean id="anotherService" class="org.xyz.SomeService"/> <!-- (not in the right package) -->
    <bean id="barManager" class="x.y.service.SimpleBarManager"/> <!-- (doesn't end in 'Service') -->

    <tx:advice id="txAdvice">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <!-- other transaction infrastructure beans such as a PlatformTransactionManager omitted... -->

</beans>
下面的配置示例演示了两个不同的bean拥有完全不同的事务配置。

<?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">

    <aop:config>

        <aop:pointcut id="defaultServiceOperation" expression="execution(* x.y.service.*Service.*(..))"/>
        <aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/>
      
        <aop:pointcut id="noTxServiceOperation" expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/>
        <aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/>

    </aop:config>

    <!-- this bean will be transactional (c.f. the 'defaultServiceOperation' pointcut) -->
    <bean id="fooService" class="x.y.service.DefaultFooService"/>

    <!-- this bean will also be transactional, but with totally different transactional settings -->
    <bean id="anotherFooService" class="x.y.service.ddl.DefaultDdlManager"/>

    <tx:advice id="defaultTxAdvice">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
  
    <tx:advice id="noTxAdvice">
        <tx:attributes>
            <tx:method name="*" propagation="NEVER"/>
        </tx:attributes>
    </tx:advice>

    <!-- other transaction infrastructure beans such as a PlatformTransactionManager omitted... -->

</beans>
9.5.5. <tx:advice/> 有关的设置
这一节里将描述通过 <tx:advice/> 标签来指定不同的事务性设置。默认的 <tx:advice/> 设置如下:


事务传播设置是 REQUIRED

隔离级别是 DEFAULT

事务是 读/写

事务超时默认是依赖于事务系统的,或者事务超时没有被支持。

任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚


这些默认的设置当然也是可以被改变的。 <tx:advice/> 和 <tx:attributes/> 标签里的 <tx:method/> 各种属性设置总结如下:


表 9.1. <tx:method/> 有关的设置

属性 是否需要? 默认值 描述
name 是   与事务属性关联的方法名。通配符(*)可以用来指定一批关联到相同的事务属性的方法。如:'get*'、'handle*'、'on*Event'等等。

propagation 不 REQUIRED 事务传播行为
isolation 不 DEFAULT 事务隔离级别
timeout 不 -1 事务超时的时间(以秒为单位)
read-only 不 false 事务是否只读?
rollback-for 不   将被触发进行回滚的 Exception(s);以逗号分开。如:'com.foo.MyBusinessException,ServletException'

no-rollback-for 不   不 被触发进行回滚的 Exception(s);以逗号分开。如:'com.foo.MyBusinessException,ServletException'

9.5.6. 使用 @Transactional
注意
@Transactional 注解及其支持类所提供的功能最低要求使用Java 5(Tiger)。

除了基于XML文件的声明式事务配置外,你也可以采用基于注解式的事务配置方法。直接在Java源代码中声明事务语义的做法让事务声明和将受其影响的代码距离更近了,而且一般来说不会有不恰当的耦合的风险,因为,使用事务性的代码几乎总是被部署在事务环境中。

下面的例子很好地演示了 @Transactional 注解的易用性,随后解释其中的细节。先看看其中的类定义:

<!-- the service class that we want to make transactional -->
@Transactional
public class DefaultFooService implements FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);
}
当上述的POJO定义在Spring IoC容器里时,上述bean实例仅仅通过一 行xml配置就可以使它具有事务性的。如下:

<!-- from the file '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">

  <!-- this is the service object that we want to make transactional -->
  <bean id="fooService" class="x.y.service.DefaultFooService"/>

  <!-- enable the configuration of transactional behavior based on annotations -->
  <tx:annotation-driven transaction-manager="txManager"/>

  <!-- a PlatformTransactionManager is still required -->
  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!-- (this dependency is defined somewhere else) -->
    <property name="dataSource" ref="dataSource"/>
  </bean>

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


</beans>
提示
实际上,如果你用 'transactionManager' 来定义 PlatformTransactionManager bean的名字的话,你就可以忽略 <tx:annotation-driven/> 标签里的 'transaction-manager' 属性。 如果 PlatformTransactionManager bean你要通过其它名称来注入的话,你必须用 'transaction-manager' 属性来指定它,如上所示。

方法的可见度和 @Transactional

@Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错,但是这个被注解的方法将不会展示已配置的事务设置。
@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 <tx:annotation-driven/>元素的出现 开启 了事务行为。

Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因此,请接受Spring团队的建议并且在具体的类上使用 @Transactional 注解。

注意
当使用 @Transactional 风格的进行声明式事务定义时,你可以通过 <tx:annotation-driven/> 元素的 "proxy-target-class" 属性值来控制是基于接口的还是基于类的代理被创建。如果 "proxy-target-class" 属值被设置为 "true",那么基于类的代理将起作用(这时需要CGLIB库cglib.jar在CLASSPATH中)。如果 "proxy-target-class" 属值被设置为 "false" 或者这个属性被省略,那么标准的JDK基于接口的代理将起作用。

在多数情形下,方法的事务设置将被优先执行。在下列情况下,例如: DefaultFooService 类被注解为只读事务,但是,这个类中的 updateFoo(Foo) 方法的 @Transactional 注解的事务设置将优先于类级别注解的事务设置。

@Transactional(readOnly = true)
public class DefaultFooService implements FooService {

    public Foo getFoo(String fooName) {
        // do something
    }

    // these settings have precedence for this method
    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public void updateFoo(Foo foo) {
        // do something
      
    }
}
9.5.6.1. @Transactional 有关的设置
@Transactional 注解是用来指定接口、类或方法必须拥有事务语义的元数据。如:“当一个方法开始调用时就开启一个新的只读事务,并停止掉任何现存的事务”。默认的 @Transactional 设置如下:

事务传播设置是 PROPAGATION_REQUIRED

事务隔离级别是 ISOLATION_DEFAULT

事务是 读/写

事务超时默认是依赖于事务系统的,或者事务超时没有被支持。

任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚

这些默认的设置当然也是可以被改变的。 @Transactional 注解的各种属性设置总结如下:


表 9.2. @Transactional 注解的属性

属性 类型 描述
传播性 枚举型:Propagation  可选的传播性设置
隔离性 枚举型:Isolation  可选的隔离性级别(默认值:ISOLATION_DEFAULT)
只读性 布尔型 读写型事务 vs. 只读型事务
超时 int型(以秒为单位) 事务超时
回滚异常类(rollbackFor) 一组 Class 类的实例,必须是Throwable 的子类 一组异常类,遇到时必须进行回滚。默认情况下checked exceptions不进行回滚,仅unchecked exceptions(即RuntimeException的子类)才进行事务回滚。
回滚异常类名(rollbackForClassname) 一组 Class 类的名字,必须是Throwable的子类一组异常类名,遇到时 必须 进行回滚
不回滚异常类(noRollbackFor) 一组 Class 类的实例,必须是Throwable 的子类 一组异常类,遇到时必须不回滚。
不回滚异常类名(noRollbackForClassname) 一组 Class 类的名字,必须是Throwable 的子类一组异常类,遇到时 必须不 回滚


9.5.7. 插入事务操作
考虑这样的情况,你有一个类的实例,而且希望同时插入事务性通知(advice)和一些简单的剖析(profiling)通知。那么,在<tx:annotation-driven/>环境中该怎么做?

我们调用 updateFoo(Foo) 方法时希望这样:

配置的剖析切面(profiling aspect)开始启动,

然后进入事务通知(根据配置创建一个新事务或加入一个已经存在的事务),

然后执行原始对象的方法,

然后事务提交(我们假定这里一切正常),

最后剖析切面报告整个事务方法执行过程花了多少时间。

注意
这章不是专门讲述AOP的任何细节(除了应用于事务方面的之外)。请参考 第 6 章使用Spring进行面向切面编程(AOP)章以获得对各种AOP配置及其一般概念的详细叙述。

这里有一份简单的剖析切面(profiling aspect)的代码。(注意,通知的顺序是由 Ordered 接口来控制的。要想了解更多细节,请参考 第 6.2.4.7 节 “通知(Advice)顺序” 节。)

package x.y;

import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
import org.springframework.core.Ordered;

public class SimpleProfiler implements Ordered {

    private int order;

    // allows us to control the ordering of advice
    public int getOrder() {
        return this.order;
    }

    public void setOrder(int order) {
        this.order = order;
    }

    // this method is the around advice
    public Object profile(ProceedingJoinPoint call) throws Throwable {
        Object returnValue;
        StopWatch clock = new StopWatch(getClass().getName());
        try {
            clock.start(call.toShortString());
            returnValue = call.proceed();
        } finally {
            clock.stop();
            System.out.println(clock.prettyPrint());
        }
        return returnValue;
    }
}

这里是帮助满足我们上述要求的配置数据。

<?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">

    <bean id="fooService" class="x.y.service.DefaultFooService"/>

    <!-- this is the aspect -->
    <bean id="profiler" class="x.y.SimpleProfiler">
        <!-- execute before the transactional advice (hence the lower order number) -->
      
        <property name="order" value="1"/>
    </bean>
  
    <tx:annotation-driven transaction-manager="txManager"/>

    <aop:config>
        <!-- this advice will execute around the transactional advice -->
        <aop:aspect id="profilingAspect" ref="profiler">
            <aop:pointcut id="serviceMethodWithReturnValue" expression="execution(!void x.y..*Service.*(..))"/>
            <aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/>
        </aop:aspect>
    </aop:config>

    <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>

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

</beans>
上面配置的结果将获得到一个拥有剖析和事务方面的 按那样的顺序 应用于它上面的 'fooService' bean。许多附加的方面的配置将一起达到这样的效果。

最后,下面的一些示例演示了使用纯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">

    <bean id="fooService" class="x.y.service.DefaultFooService"/>

    <!-- the profiling advice -->
    <bean id="profiler" class="x.y.SimpleProfiler">
        <!-- execute before the transactional advice (hence the lower order number) -->
        <property name="order" value="1"/>
    </bean>

    <aop:config>

        <aop:pointcut id="entryPointMethod" expression="execution(* x.y..*Service.*(..))"/>

        <!-- will execute after the profiling advice (c.f. the order attribute) -->
     
        <aop:advisor advice-ref="txAdvice" pointcut-ref="entryPointMethod"order="2"/>
      
        <!-- order value is higher than the profiling aspect -->

        <aop:aspect id="profilingAspect" ref="profiler">
            <aop:pointcut id="serviceMethodWithReturnValue" expression="execution(!void x.y..*Service.*(..))"/>
            <aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/>
        </aop:aspect>

    </aop:config>

    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <!-- other <bean/> definitions such as a DataSource and a PlatformTransactionManager here -->

</beans>
上面配置的结果是创建了一个 'fooService' bean,剖析方面和事务方面被依照顺序施加其上。如果我们希望剖析通知在目标方法执行之前 后于 事务通知执行,而且在目标方法执行之后先于事务通知,我们可以简单地交换两个通知bean的order值。

如果配置中包含更多的方面,它们将以同样的方式受到影响。

9.5.8. 结合AspectJ使用 @Transactional
通过AspectJ切面,你也可以在Spring容器之外使用Spring框架的 @Transactional 功能。要使用这项功能你必须先给相应的类和方法加上 @Transactional注解,然后把 spring-aspects.jar 文件中定义的 org.springframework.transaction.aspectj.AnnotationTransactionAspect 切面连接进(织入)你的应用。同样,该切面必须配置一个事务管理器。你当然可以通过Spring框架容器来处理注入,但因为我们这里关注于在Spring容器之外运行应用,我们将向你展示如何通过手动书写代码来完成。

注意
在我们继续之前,你可能需要好好读一下前面的第 9.5.6 节 “使用 @Transactional” 和 第 6 章使用Spring进行面向切面编程(AOP) 两章。

// construct an appropriate transaction manager
DataSourceTransactionManager txManager = new DataSourceTransactionManager(getDataSource());

// configure the AnnotationTransactionAspect to use it; this must be done before executing any transactional methods
AnnotationTransactionAspect.aspectOf().setTransactionManager (txManager);
注意
使用此切面(aspect),你必须在 实现 类(和/或类里的方法)、而不是类的任何所实现的接口上面进行注解。AspectJ遵循Java的接口上的注解 不被继承 的规则。

类上的 @Transactional 注解指定了类里的任何 public 方法执行的默认事务语义。

类里的方法的 @Transactional 将覆盖掉类注解的默认事务语义(如何存在的话)。 public、protected和默认可见的方法可能都被注解。直接对 protected和默认可见的方法进行注解,让这些方法在执行时去获取所定义的事务划分是唯一的途径。

要把 AnnotationTransactionAspect 织入你的应用,你或者基于AspectJ构建你的应用(参考 AspectJ Development Guide),或者采取“载入时织入”(load-time weaving),参考 第 6.8.4 节 “在Spring应用中使用AspectJ Load-time weaving(LTW)” 获得关于使用AspectJ进行“载入时织入”的讨论。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/mmm123lmj/archive/2009/10/09/4646717.aspx

分享到:
评论

相关推荐

    ssh框架事务管理applicationContext.xml配置文件

    ssh框架事务管理applicationContext.xml配置文件

    在SSH框架中加入事务支持

    本文将深入探讨如何在SSH框架中加入事务支持,特别是当Spring版本为2.0时。 首先,我们需要理解事务管理在企业级应用中的重要性。事务确保了数据的一致性和完整性,通过ACID(原子性、一致性、隔离性和持久性)属性...

    SSH框架搭建源码

    SSH框架,全称为Struts2、Spring和Hibernate的组合,是Java Web开发中常见的三大开源框架集成。这个压缩包文件"SSHdemo"提供了一个SSH框架搭建登录功能的示例,帮助开发者了解并实践如何整合这三个框架来构建一个...

    带事务的ssh框架源代码

    在这个“带事务的ssh框架源代码”中,我们将会探讨SSH框架如何处理数据库事务,以及不同版本的Spring(1.2、2.5、3.2)在事务管理上的差异。 首先,Struts作为表现层框架,主要负责用户界面与控制器之间的交互。它...

    Java SSH 框架整合,学习源码

    8. **实战经验**:在实际项目中,开发者需要关注性能优化、事务管理、异常处理等问题,这都需要对SSH框架有深入的理解。例如,合理使用Spring的AOP进行事务管理,避免Struts的性能瓶颈,以及优化Hibernate的查询性能...

    ssh框架纯净版

    在实际开发中,SSH框架的集成使得开发者能高效地进行业务逻辑处理,同时Spring的事务管理功能可以确保数据一致性。通过阅读提供的文件,开发者可以深入理解SSH框架的工作原理,并将其应用于实际项目中,提高开发效率...

    SSH框架整合项目源码

    SSH框架,全称为Struts2、Spring和Hibernate的组合,是Java Web开发中常见的三大开源框架集成。这个项目源码提供了SSH整合的实践案例,特别适合初学者学习和理解Web应用的开发流程。 Struts2作为MVC(Model-View-...

    SSH框架JAR包集合

    SSH框架,全称为Spring、Struts和Hibernate,是Java Web开发中的一个经典组合,用于构建高效、可维护的Web应用程序。这些框架各自负责不同的职责,Spring作为基础架构框架,Struts处理视图与控制,Hibernate则专注于...

    ssh事务处理

    为了在SSH框架中进行事务管理,我们需要配置一个`HibernateTransactionManager`,该类实现了Spring的`PlatformTransactionManager`接口,可以用来管理基于Hibernate的事务。 ```xml ``` ##### 4. 事务代理...

    ssh框架jar包整合

    SSH框架,全称为Struts2、Spring和Hibernate的组合,是Java Web开发中常见的三大框架。这三大框架分别负责表现层、业务层和持久层的管理,为开发者提供了高效、灵活且可扩展的开发环境。在Java Web项目中,SSH框架的...

    SSH框架整合jar包

    SSH框架整合是Java Web开发中常见的一种技术栈组合,它由Spring、Struts2和Hibernate三个框架构成。这个"SSH框架整合jar包"是开发者为了方便项目构建,避免手动逐个添加和配置这三个框架所需的库文件而制作的集合。...

    毕业设计 基于SSH框架的系统

    【标题】"基于SSH框架的系统"是一种常见的企业级应用开发模式,SSH分别代表Spring、Struts和Hibernate三个开源框架的首字母缩写。Spring作为核心的IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented ...

    SSH框架搭建步骤

    SSH框架,全称为Spring、Struts和Hibernate的首字母缩写,是Java开发中的一个经典组合,用于构建企业级Web应用程序。Spring提供了依赖注入(DI)和面向切面编程(AOP),Struts则处理MVC(模型-视图-控制器)架构,...

    ssh 框架搭建 pdf

    整合SSH框架需要进行一些配置工作,例如在Spring的配置文件中声明Hibernate的SessionFactory和事务管理器,以及配置Struts与Spring的整合,让Struts的Action能够使用Spring管理的DAO(数据访问对象)和Service(服务...

    SSH框架整合的jar包

    SSH框架,全称为Struts2、Spring和Hibernate的组合,是Java Web开发中常见的三大开源框架集成。它们分别负责表现层、业务层和服务层的管理,构建了一个完整的MVC(Model-View-Controller)架构。下面将详细介绍这三...

    ssh框架开发短信平台

    SSH框架,全称为Struts2、Spring和Hibernate的组合,是Java Web开发中常用的一套集成框架。这个框架集合了MVC(Model-View-Controller)设计模式的Struts2,依赖注入和面向切面编程的Spring,以及持久层管理的...

    SSH框架的学习资料

    SSH框架是Java开发中常用的三大框架,包括Struts2、Spring和Hibernate,它们协同工作,为Web应用程序提供了模型-视图-控制器(MVC)架构的支持。这些框架各自有着独特的功能,结合使用能够极大地提高开发效率和代码...

    SSH框架搭建jar包

    SSH框架,全称为Struts2、Spring和Hibernate的组合,是Java Web开发中常见的三大开源框架。它们分别负责表现层、业务层和服务层的管理,为开发者提供了强大的功能和灵活的架构。本压缩包提供了搭建SSH环境所需的核心...

    商贸项目SSH框架实现代码

    【SSH框架详解】 SSH框架是Java Web开发中的一个经典组合,由Spring、Struts和Hibernate三个开源框架集成,常用于构建企业级应用。这个“商贸项目SSH框架实现代码”提供了完整的源码,对于学习和理解SSH框架的工作...

    淘宝网站 ssh框架

    SSH框架在IT行业中指的是Spring、Struts和Hibernate这三个开源框架的组合,它们是Java Web开发中的常用工具。淘宝网站作为中国最大的电商平台,其后端架构很可能就采用了SSH框架来构建,以实现高效、稳定和可扩展的...

Global site tag (gtag.js) - Google Analytics