声明式事务管理
大多数 Spring 框架用户选择声明式事务管理。这种选择对应用程序代码的影响最小,因此最符合非侵入式轻量级容器的理念。
Spring 框架的声明式事务管理是通过 Spring 面向切面编程(AOP)实现的。然而,由于事务切面代码随 Spring 框架发行版提供,并且可以以样板方式使用,因此通常不需要理解 AOP 概念即可有效使用此代码。
Spring 框架的声明式事务管理与 EJB CMT 类似,因为你可以将事务行为(或不包含事务行为)指定到单个方法级别。如果需要,你可以在事务上下文中调用 setRollbackOnly()。这两种事务管理类型之间的区别是:
-
与 EJB CMT 不同,后者与 JTA 绑定,Spring 框架的声明式事务管理适用于任何环境。它可以通过调整配置文件与 JTA 事务或本地事务(使用 JDBC、JPA 或 Hibernate)一起工作。
-
你可以将 Spring 框架的声明式事务管理应用于任何类,而不仅仅是像 EJB 这样的特殊类。
-
Spring 框架提供了声明式的回滚规则,这是一个 EJB 没有等效功能。Spring 提供了对回滚规则的编程式和声明式支持。
-
Spring 框架允许你通过使用 AOP 自定义事务行为。例如,你可以在事务回滚的情况下插入自定义行为。你还可以在事务通知之外添加任意的通知。而在 EJB CMT 中,除了使用
setRollbackOnly()之外,你无法影响容器的事务管理。 -
Spring 框架不支持像高端应用服务器那样跨远程调用传播事务上下文。如果你需要这一功能,我们建议你使用 EJB。然而,在使用此类功能之前请仔细考虑,因为通常情况下,人们不希望事务跨越远程调用。
回滚规则的概念非常重要。它们允许你指定哪些异常(和可抛出对象)应该导致自动回滚。你可以在配置中以声明方式指定这一点,而不是在 Java 代码中。因此,尽管你仍然可以在 TransactionStatus 对象上调用 setRollbackOnly() 来回滚当前事务,但大多数情况下,你可以指定一个规则,即 MyApplicationException 必须始终导致回滚。这种选项的显著优势是业务对象不依赖于事务基础架构。例如,它们通常不需要导入 Spring 事务 API 或其他 Spring API。
尽管 EJB 容器的默认行为会在系统异常(通常是运行时异常)时自动回滚事务,但 EJB CMT 在应用程序异常(即除了 java.rmi.RemoteException 之外的已检查异常)时不会自动回滚事务。虽然 Spring 的声明式事务管理默认行为遵循 EJB 约定(仅对未检查的异常自动回滚),但自定义此行为通常很有用。
章节摘要
理解 Spring 框架的声明式事务实现
仅仅告诉你使用 @Transactional 注解来标注你的类,并在配置中添加 @EnableTransactionManagement,然后期望你理解这一切是如何工作的,这是不够的。为了提供更深入的理解,本节将在与事务相关的问题背景下,解释 Spring 框架声明式事务基础设施的内部工作原理。
声明式事务实现示例
考虑以下接口及其伴随的实现。本示例使用 Foo 和 Bar 类作为占位符,以便您可以专注于事务的使用,而不必关注特定的领域模型。出于本示例的目的,DefaultFooService 类在每个实现方法的主体中抛出 UnsupportedOperationException 实例是合理的。这种行为让您可以看到事务被创建,然后由于 UnsupportedOperationException 实例而被回滚。以下代码展示了 FooService 接口:
回滚声明式事务
上一节概述了如何在应用程序中以声明方式为类(通常是服务层类)指定事务设置的基础知识。本节描述了如何在 XML 配置中以简单、声明的方式控制事务的回滚。有关使用 @Transactional 注解以声明方式控制回滚语义的详细信息,请参阅 @Transactional 设置。
为不同的 Bean 配置不同的事务语义
考虑这样一个场景:你有多个服务层对象,并且你想为每个对象应用完全不同的事务配置。你可以通过定义具有不同 pointcut 和 advice-ref 属性值的不同 \<aop:advisor/> 元素来实现这一点。
tx:advice/ 设置
本节总结了您可以使用 \<tx:advice/> 标签指定的各种事务设置。默认的 \<tx:advice/> 设置如下:
使用 @Transactional
除了基于 XML 的声明式事务配置方法外,您还可以使用基于注解的方法。直接在 Java 源代码中声明事务语义,使得声明更接近受影响的代码。由于事务性代码几乎总是以这种方式部署,因此不太可能出现不适当的耦合问题。
事务传播
本节描述了 Spring 中事务传播的一些语义。请注意,本节并不是对事务传播的正式介绍,而是详细说明了 Spring 中有关事务传播的一些语义。
事务操作建议
假设您希望同时运行事务操作和一些基本的性能分析建议。在 \<tx:annotation-driven/> 的上下文中,您如何实现这一点?
使用 AspectJ 的 @Transactional
你也可以通过使用 AspectJ 切面在 Spring 容器之外使用 Spring 框架的 @Transactional 支持。为此,首先用 @Transactional 注解标注你的类(以及可选的类方法),然后将你的应用程序与定义在 spring-aspects.jar 文件中的 org.springframework.transaction.aspectj.AnnotationTransactionAspect 进行链接(织入)。你还必须为切面配置一个事务管理器。你可以使用 Spring 框架的 IoC 容器来处理切面的依赖注入。配置事务管理切面的最简单方法是使用 \<tx:annotation-driven/> 元素,并将 mode 属性指定为 aspectj,如使用 @Transactional 中所述。因为我们在这里关注的是在 Spring 容器之外运行的应用程序,所以我们向你展示如何以编程方式实现这一点。