声明式事务管理
大多数 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 容器之外运行的应用程序,所以我们向你展示如何以编程方式实现这一点。