`
yuanfen860913
  • 浏览: 119920 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

使用 @Transactional

阅读更多

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/KOOK_OKKO/archive/2009/09/19/4565805.aspx

分享到:
评论

相关推荐

    Spring3事务管理——使用@Transactional 注解.rar

    - 尽可能地在细粒度的层面上使用`@Transactional`,避免在整个服务类上使用,以提高事务控制的灵活性。 - 考虑使用`@Transactional(readOnly = true)`来标记只读事务,这样Spring可以优化事务处理,比如跳过回滚...

    后端 Java Spring Data Jpa @Transactional 介绍

    在Java后端开发中,Spring框架提供了强大的事务管理能力,特别是在使用Spring Data JPA时,`@Transactional`注解使得事务处理变得简单易用。这个注解是Spring框架中的核心部分,它允许开发者声明性地控制事务边界,...

    springboot中事务管理@Transactional的注意事项与使用场景

    SpringBoot 中事务管理 @Transactional 的注意事项与使用场景 在本篇文章中,我们将详细讲解 SpringBoot 中事务管理 @Transactional 的注意事项与使用场景,以帮助开发者更好地理解和使用 @Transactional 注解。 ...

    @Transactional实现原理.txt

    @Transactional实现原理.txt

    Spring声明式事务@Transactional知识点分享

    * 如果在类上使用 @Transactional 注解,那么该类中的所有方法都会继承该注解的属性。 * 如果在方法上使用 @Transactional 注解,那么该方法将覆盖类上的注解属性。 @Transactional 注解是 Spring 框架中实现声明式...

    Spring @Transactional工作原理详解

    首先,`@Transactional`的使用简化了事务管理。当在方法上标注`@Transactional`时,Spring会自动在方法执行前后管理事务边界。这意味着,如果方法内部发生异常,事务会被回滚;反之,如果方法正常执行完毕,事务则会...

    Spring中@Transactional事务回滚(含实例

    以下是一个简单的示例,展示如何使用`@Transactional`实现事务回滚: ```java @Service public class UserService { @Autowired private UserRepository userRepository; @Transactional(rollbackFor = ...

    浅谈Spring中@Transactional事务回滚及示例(附源码)

    本文将详细介绍@Transactional的使用场景、checked异常和unchecked异常的概念、@Transactional的使用实例等内容。 一、使用场景 在了解@Transactional怎么用之前,我们必须要先知道@Transactional有什么用。例如,...

    什么情况会导致@Transactional事务失效?

    1. **未启用事务管理**:如果你的应用没有配置Spring的事务管理器(如PlatformTransactionManager),或者没有开启AOP代理(例如,使用@Component而不是@Service等),`@Transactional`将无法生效。确保你的配置类...

    spring @Transactional 无效的解决方案

    首先,让我们来了解一下@Transactional注解的使用规则: 1. 在需要事务管理的地方加@Transactional 注解。 2. @Transactional 注解只能应用到 public 可见度的方法上。 3. 注意仅仅 @Transactional 注解的出现不足...

    深入学习Spring Boot排查 @Transactional 引起的 NullPointerException问题

    然而,在某些情况下,使用 @Transactional 注解可能会引起 NullPointerException,这是一个非常棘手的问题。本文将深入探讨 Spring Boot 中 @Transactional 引起的 NullPointerException 问题,并提供解决方案。 ...

    spring 自定义事务管理器,编程式事务,声明式事务@Transactional使用

    本教程将深入探讨如何在Spring中实现自定义事务管理器、编程式事务处理以及声明式事务`@Transactional`的使用。 首先,让我们了解事务管理的基本概念。事务是一组数据库操作,这些操作要么全部执行,要么全部回滚,...

    Transactional所需要的jar包:

    1、aopalliance.jar 这个包是AOP联盟的API包,里面包含了针对面向切面的接口。(通常Spring等其它具备动态织入功能的框架依赖此包) 2、aspectjrt.jar 处理事务和AOP所需的包 3、aspectjweaver.jar 处理事务和AOP所需...

    Spring @Transactional注解失效解决方案

    如果是 MySQL,需要使用支持事务的引擎,例如 InnoDB。 4. 确认是否开启了对注解的解析,例如在 Spring 配置文件中添加 。 通过了解 @Transactional 注解的特性和事务传播模式,并遵循解决方案,我们可以解决 @...

    Java注解@Transactional事务类内调用不生效问题及解决办法

    Java注解@Transactional事务类内调用不生效问题及解决办法 Java注解@Transactional是Java中的一种注解,主要用于...然而,在某些情况下,@Transactional注解可能不会生效,需要使用AspectJ对方法进行切面来解决问题。

    带有@Transactional和@Async的循环依赖问题

    2. 调整注解使用:如果循环依赖无法避免,可以考虑将`@Transactional`和`@Async`注解分开,不要同时应用于同一个方法。例如,可以将事务管理应用于一组服务方法,而将异步执行应用于另一组方法。 3. 修改配置:在...

    Spring中的@Transactional事物回滚实例源码

    1. **AOP代理**:Spring使用AOP(面向切面编程)来拦截带有`@Transactional`的方法调用。 2. **事务初始化**:当代理方法被调用时,Spring会检查当前是否存在事务。如果没有,就会根据注解上的配置启动一个新的事务...

    spring-@Transactional-jar

    spring事务管理注解jar,spring-tx-3.2.4.RELEASE.jar,导入项目即可

Global site tag (gtag.js) - Google Analytics