您的位置:首页 > 编程语言 > Java开发

Spring 学习笔记 (IV) 之 Spring 的事务

2015-12-30 17:09 267 查看

Spring的事务

1、Spring 的事务管理不需要与任何特定的事务 API 耦合。对不同的持久层访问技术,编程式事务提供一致的事务编程风格,通过模板化的操作一致性地管理事务。声明式事务基于 Spring AOP
实现,却并不需要程序开发者成为AOP 专家,亦可轻易使用 Spring 的声明式事务管理。

2、Java EE 应用的传统事务有两种策略:全局事务和局部事务,全局事务由应用服务器管理,需要底层服务器的 JTA 支持。局部事务和底层所采用的持久化技术有关,当采用 JDBC 持久化技术时,需要使用 Connection 对象来操作事务;而采用 Hibernate 持久化技术时,需要使用 Session 对象来操作事务。

3、全局事务可以跨多个事务性的资源(典型例子是关系数据和消息队列);使用局部事务,应用服务器不需要参与事务管理,因此不能保证跨多个事务性资源的事务的正确性。当然,实际上大部分应用都使用单一事务性的资源。

4、当采用传统的事务编程策略时,程序代码必然和具体的事务操作代码耦合,这样造成的后果是:当应用程序需要在不同的事务策略之间切换时,开发者必须手动修改程序代码。当使用 Spring
事务操作策略后,就可以改变这种现状。

5、Spring 事务策略是通过 PlatformTransactionManager 接口体现的,该接口是 Spring 事务策略的核心。

6、PlatformTransactionManager是一个与任何事务策略分离的接口,随着底层不同事务策略的切换,应用必须采用不同的实现类。PlatformTransactionManager 接口没有与任何事务资源捆绑在一起,它可以适应于任何的事务策略,结合 Spring 的 IoC 容器,可以向 PlatformTransactionManager 注入相关的平台特性。

7、PlatformTransactionManager接口有许多不同的实现类,应用程序面向于平台无关的接口编程,当底层采用不同的持久层技术时,系统只需使用不同的 PlatformTransactionManager 实现类即可——而这种切换通常由Spring 容器负责管理,应用程序既无须与具体的事务
API 耦合,也无须与特定实现类耦合,从而将应用和持久化技术、事务 API
彻底分离开来。

8、Spring 的事务管理机制是一种典型的策略模式,PlatformTransactionManager 代表事务管理接口,但它并不知道底层到底如何管理事务,它只要求事务管理需要提供开始事务(getTransaction())、提交事务(commit())和回滚事务(rollback())三个方法,但具体如何实现则交给其实现类来完成——不同实现类则代表不同的事务管理策略。

9、Spring 事务管理的优势是将应用从具体的事务 API 中分离出来,而不是真正提供事务管理的底层实现。

10、在PlatformTransactionManager 接口内,包含一个 getTransaction(TransactionDefinition definition)方法,该方法根据一个TransactionDefinition 参数,返回一个 TransactionStatus 对象。TransactionStatus
对象表示一个事务,TransactionStatus
被关联在当前执行的线程上。

11、getTransaction(TransactionDefinitiondefinition)返回的 TransactionStatus 对象,可能是一个新的事务,也可能是一个已经存在的事务对象。如果当前执行的线程已经处于事务管理下,则返回当前线程的事务对象;否则,系统将新建一个事务对象后返回。

12、TransactionDefinition接口定义了一个事务规则,该接口必须指定如下几个属性值。

事务隔离:当前事务和其他事务的隔离程度。例如,这个事务能否看到其他事务未提交的数据等。
事务传播:通常,在事务中执行的代码都会在当前事务中运行。但是,如果一个事务上下文已经存在,有几个选项可指定该事务性方法的执行行为。例如,大多数情况下,简单地在现有的事务上下文中运行;或者挂起现有事务,创建一个新的事务。Spring 提供 EJB CMT(Contain Manager Transaction,容器管理事务)中所有的事务传播选项。
事务超时:事务在超时前能运行多久,也就是事务的最长持续时间。如果事务一直没有被提交或回滚,将在超出该时间后,系统自动回滚事务。
只读状态:只读事务不修改任何数据。在某些情况下(例如使用 Hibernate 时),只读事务是非常有用的优化。
13、TransactionStatus 代表事务本身,它提供了简单的控制事务执行和查询事务状态的方法,这些方法在所有的事务 API 中都是相同的。

14、Spring 具体的事务管理由PlatformTransactionManager 的不同实现类来完成。在
Spring 容器中配置PlatformTransactionManager Bean
时,必须针对不同环境提供不同的实现类。

15、当配置 JtaTransactionManager全局事务管理策略时,只需指定事务管理器实现类即可,无须传入额外的事务资源。这是因为全局事务的 JTA 资源由 Java EE 服务器提供,而Spring
容器能自行从 Java EE
服务器中获取该事务资源,所以无须使用依赖注入来配置。

16、不论采用哪种持久层访问技术,只要使用JTA 全局事务,Spring 事务管理的配置完全一样,因为它们采用的都是全局事务管理策略。

17、注意:当采用 JTA 全局事务策略时,实际上需要底层应用服务器的支持,而不同应用服务器所提供的 JTA 全局事务可能存在细节上的差异,因此实际配置全局事务管理器时可能需要使用 JtaTransactionManager 的子类,如 OC4JjtaTransactionManager(Oracle 提供的 JavaEE 应用服务器)、WebLogicJtaTransactionManger(Bea
提供的 WebLogic)、WebSphereUowTransactionManager(IBM 提供的 WebSphere)等,他们分别对应于不同的应用服务器。

18、当采用 Spring 事务管理策略时,应用程序无须与具体的事务策略耦合。Spring 提供了如下两种事务管理方式。

编程式事务管理:即使利用 Spring 编程式事务时,程序也可直接获取容器中的 transactionManager Bean,该 Bean 总是PlatformTransactionManager 的实例,所以可以通过该接口所提供的 3 个方法来开始事务、提交事务和回滚事务。
声明式事务管理:无须在 Java 程序中书写任何的事务操作代码,而是通过在 XML 文件中为业务组件配置事务代理(AOP 代理的一种),AOP 为事务代理所织入的增强处理也由 Spring 提供:在目标方法执行之前,织入开始事务;在目标方法执行之后,织入结束事务。
不论采用何种持久化策略,Spring 都提供了一致的事务抽象,因此,应用开发者能在任何环境下,使用一致的编程模型。无须更改代码,应用就可以在不同的事务管理策略中切换。

19、当使用编程式事务时,开发者使用的是Spring 事务抽象(面向 PlatformTransactionManager 接口编程),而无须使用任何具体的底层事务API。Spring 的事务管理将代码从底层具体的事务 API 中抽象出来,该抽象能以任何底层事务为基础。

20、提示:Spring 编程式事务还可通过TransactionTemplate 类来完成,该类提供了一个 execute(TransactionCallback action)方法,可以以更简洁的方式来进行事务操作。

21、当使用声明式事务时,开发者无须书写任何事务管理代码,不依赖 Spring 或任何其他事务 API。Spring 的声明式事务无须任何额外的容器支持,Spring 容器本身管理声明式事务。使用声明式事务策略,可以让开发者更好地专注于业务逻辑的实现。

22、注意:Spring 所支持的事务策略非常灵活,Spring 的事务策略允许应用程序在不同事务策略之间自由切换,即使需要在局部事务策略和全局事务策略之间切换,只需要修改配置文件即可,而应用程序的代码无须任何改变。这种灵活的设计,正是面向接口编程带来的优势。

23、Spring 同时支持编程式事务策略和声明式事务策略,大部分时候,我们都推荐采用声明式事务策略。使用声明式事务策略的优势十分明显:

声明式事务能大大降低开发者的代码书写量,而且声明式事务几乎不影响应用的代码。因此,无论底层事务策略如何变化,应用程序都无须任何改变。
应用程序代码无须任何事务处理代码,可以更专注于业务逻辑的实现。
Spring 则可对任何 POJO 的方法提供事务管理,而且 Spring 的声明式事务管理无须容器的支持,可在任何环境下使用。
EJB 的 CMT 无法提供声明式回滚规则:而通过配置文件,Spring 可指定事务在遇到特定异常时自动回滚。Spring 不仅可在代码中使用 setRollbackOnly 回滚事务,也可在配置文件中配置回滚规则。
由于 Spring 采用 AOP 的方式管理事务,因此,可以在事务回滚动作中插入用户自己的动作,而不仅仅是执行系统默认的回滚。
24、在 Spring 1.X 中,声明式事务使用TransactionProxyFactoryBean 来配置事务代理 Bean。正如它的类名所暗示的,它是一个工厂 Bean,该工厂 Bean 专门为目标 Bean 生成事务代理。每个 TransactionProxyFactoryBean 为一个目标 Bean 生成一个事务代理 Bean,事务代理的方法改写了目标Bean 的方法,就是在目标 Bean 的方法执行之前加入开始事务,在目标 Bean 的方法正常结束之前提交事务,如果遇到特定异常则回滚事务。

25、TransactionProxyFactoryBean创建事务代理时,需要了解当前事务所处的环境,该环境属性通过PlatformTransactionManager
实例(其实现类的实例)传入,而相关事务规则则在该 Bean
定义中给出。

26、配置事务代理时需要传入一个事务管理器、一个目标 Bean,并指定该事务代理的事务属性,事务属性由 transactionAttributes 属性指定。Spring 支持的事务传播规则如下。

PROPAGATION_MANDATORY:要求调用该方法的线程必须处于事务环境下,否则抛出异常。
PROPAGATION_NESTED:如果执行该方法的线程已处于事务环境下,依然启动新的事务,方法在嵌套的事务里执行。如果执行该方法的线程并未处于事务中,也启动新的事务,然后执行该方法,此时与 PROPAGATION_REQUIRED 相同。
PROPAGATION_NEVER:不允许调用该方法的线程处于事务环境下,如果调用该方法的线程处于事务环境下,则抛出异常。
PROPAGATION_NOT_SUPPORTED:如果调用该方法的线程处在事务中,则先暂停当前事务,然后执行该方法。
PROPAGATION_REQUIRED:要求在事务环境中执行该方法,如果当前执行线程已处于事务中,则直接调用;如果当前线程不处于事务中,则启动新的事务后执行该方法。
PROPAGATION_REQUIRES_NEW:该方法要求在新的事务环境中执行,如果当前执行线程已处于事务中,则先暂停当前事务,启动新事务后执行该方法;如果当前调用线程不处于事务中,则启动新的事务后执行方法。
PROPAGATION_SUPPORTS:如果当前执行线程处于事务中,则使用当前事务,否则不使用事务。
27、事实上,Spring 不仅支持对接口的代理,整合CGLIB 后,Spring 甚至可对具体类生成代理,只要设置 proxyTargetClass 属性为 true 就可以。如果目标 Bean 没有实现任何接口,proxyTargetClass 属性默认被设为 true,此时 Spring 会对具体类生成代理。当然,通常建议面向接口编程,而不要面向具体的实现类编程。

28、Spring 2.X 的 XML Schema 方式提供了更简洁的事务配置策略,Spring 2.X 提供了 tx 命令空间来配置事务管理,tx
命令空间下提供了<tx:advice.../>元素来配置事务增强处理,一旦使用该元素配置了事务增强处理,就可直接使用<aop:advisor.../>元素启用自动代理了。

29、配置<tx:advice.../>元素时只需指定一个transaction-manager 属性,该属性的默认值是’transactionManager’。

30、提示:如果事务管理器 Bean(PlatformTransactionManager实现类)的名字是 transactionManager,则配置<tx:advice.../>元素时完全可以省略指定 transaction-manager 属性。只有当我们为事务管理器 Bean 指定了其他名字时,才需要为<tx:advice.../>元素指定 transaction-manager 属性。

31、提示:<aop:advisor.../>元素之一个很奇怪的东西,它用于配置一个 Advisor,但标准的 AOP 概念里并没有所谓的“Advisor”,Advisor 是 Spring 1.X 遗留下来的一个东西。Advisor
的作用非常简单:将 Advice
和切入点(即可通过 pointcut-ref
指定一个已有的切入点,也可通过 pointcut
指定切入点表达式)绑定在一起,保证 Advice
所包含的增强处理将在对应的切入点被织入。

31、当采用<aop:advisor.../>元素将 Advice 和切入点绑定时,实际上是由 Spring 提供的 Bean 后处理器完成的。Spring 提供了 BeanNameAutoProxyCreator、DefaultAdvisorAutoProxyCreator两个 Bean 后处理器,它们都可以后处理容器中的 Bean(为它们织入切面中包含的处理)。前面我们配置<aop:advisor.../>元素时传入一个 txAdvice 事务增强处理,所以Bean 后处理器将为所有 Bean 实例里匹配切入点的方法织入事务操作的增强处理。

32、配置<tx:advice.../>元素时除了需要一个transaction-manager 属性之外,重要的是需要配置一个 <attributes.../>子元素,该子元素里又包含多个<method.../>子元素。

33、配置<tx:advice.../>元素的重点就是配置<method.../>子元素,实际上每个<method.../>子元素为一批方法指定所需的事务语义,包括事务传播属性、事务隔离属性、事务超时属性、只读属性、对指定异常回滚、对指定异常不回滚等。

配置<method.../>子元素可以指定如下几个属性。

name:必选属性,与该事务语义关联的方法名。该属性支持使用通配符。例如’get*’、’handle*’、’on*Event’等。
propagation:指定事务传播行为,该属性值可为 Propagation 枚举类的任一枚举值,各枚举值的含义和 8.5.2 节的介绍完全一样。该属性的默认值为 Propagation.REQUIRED。
isolation:指定事务隔离级别,该属性值可为 Isolation 枚举类的任一枚举值,各枚举值的具体含义可参考 API 文档。该属性的默认值可为 Isolation.DEFAULT。
timeout:指定事务超时时间(以秒为单位),指定 -1 意味着不超时,该属性的默认值是 -1。
read-only:指定事务是否只读。该属性的默认值是 false。
rollback-for:指定触发事务回滚的异常类(应使用全限定类名),该属性可指定多个异常类,多个异常类之间以英文逗号隔开。
no-rollback-for:指定不触发事务回滚的异常类(应使用全限定类名),该属性可指定多个异常类,多个异常类之间以英文逗号隔开。
34、提示:在默认情况下,只有当抛出运行时异常和 unChecked 异常时,Spring 事务框架才会自动回滚事务。也就是说,只有当抛出一个 RuntimeException 或器子类实例,以及 Error 对象,Spring 才会自动回滚事务。如果事务方法中抛出 Checked 异常,则事务不会自动回滚。

使用 @Transactional

35、Spring 还允许将事务配置设置放在 Java 类中定义,这需要借助于 @Transactinal Annotation,该 Annotation 既可用于修饰 SpringBean 类,也可用于修饰 Bean 类中的某个方法。

36、如果使用 @Transactional 修饰 Bean 类,表明这些事务设置对整个 Bean 类起作用;如果使用 @Transactional 修饰 Bean 类的某个方法,表明这些事务设置只对该方法有效。

37、使用 @Transactional 时可指定如下方法。

isolation:用于指定事务的隔离级别。默认为底层事务的隔离级别。
oRollbackFor:指定遇到指定异常时强制不回滚事务。
noRollbackForClassName:指定遇到指定多个异常时强制不回滚事务。该属性可以指定多个异常类名。
propagation:指定事务传播属性。
readOnly:指定事务是否只读。
rollbackFor:指定遇到指定异常时强制回滚事务。
rollbackForClassName:指定遇到指定多个异常时强制回滚事务。该属性值可以指定多个异常类名。
timeout:指定事务的超时时长。
根据上面的解释不难看出,其实该 Annotation 所指定的属性与<tx:advice.../>元素中能指定的事务属性基本上是对应的,它们的意义也基本相似。

38、Spring 配置文件中根据 Annotation 来生成事务代理。

<!-- 根据 Annotation 来生成事务代理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: