TransactionDefinition接口

16.2.1 探索TransactionDefinition接口

正如之前所说的,TransactionDefinition接口控制着事务的属性。下面让我们进一步看看该接口及其方法,如代码清单16-1所示:

代码清单16-1 TransactionDefinition接口

 

接口中简单而明显的方法是getTimeout()方法,它返回一个事务必须完成的时间限制(以秒为单位),还有isReadOnly()方法,它表示事务是否只读。事务管理器的实现可以利用这个值来优化事务的执行,并确保事务只进行读取操作。

另外两个方法--getPropagationBehavior()与getIsolationLevel()需要深入讨论。我们先介绍getIsolationLevel(),它对其他事务所能看到的数据变化进行控制。表16-1列出了你可以使用的事务隔离级别,并说明了其他事务可以访问的当前事务变化。

表16-1 事务隔离级别

隔离级别

说明

TransactionDefinition.

 ISOLATION_DEFAULT

PlatformTransactionManager

的默认隔离级别(对大多数数据库

来说就是ISOLATION_ READ_COMMITTED)

TransactionDefinition. ISOLATION_READ_UNCOMMITTED

最低的隔离级别。事实上我们不应该

称其为隔离级别,因为在事务完成前,

其他事务可以看到该事务所修改的数据。

而在其他事务提交前,该事务也可以看到

其他事务所做的修改

TransactionDefinition. ISOLATION_READ_COMMITTED

大多数数据库的默认级别。在事务完成前,

其他事务无法看到该事务所修改的数据。

遗憾的是,在该事务提交后,你就可以查

看其他事务插入或更新的数据。这意味

着在事务的不同点上,如果其他事务修改

了数据,你就会看到不同的数据

TransactionDefinition. ISOLATION_REPEATABLE_READ

比ISOLATION_READ_COMMITTED更严格,

该隔离级别确保如果在事务中查询了某个

数据集,你至少还能再次查询到相同的数

据集,即使其他事务修改了所查询的数据。

然而如果其他事务插入了新数据,

你就可以查询到该新插入的数据

TransactionDefinition. ISOLATION_SERIALIZABLE

代价最大、可靠性最高的隔离级别,

所有的事务都是按顺序一个接一个地执行

选择合适的隔离级别对于保证数据的一致性非常重要,并且所作出的选择会对性能产生重大影响。最高的隔离级别TransactionDefinition.ISOLATION_SERIALIZABLE开销最大。

getPropagationBehavior()方法指定了当代码请求一个新的事务时Spring所做的事情。表16-2列出了这个方法的常量值。

表16-2 传播行为值

传播行为

说明

TransactionDefinition. 

PROPAGATION_REQUIRED

当前如果有事务,Spring就会使用该事务;

否则会开始一个新事务

TransactionDefinition. 

PROPAGATION_SUPPORTS

当前如果有事务,Spring就会使用该事务;

否则不会开始一个新事务

TransactionDefinition. 

PROPAGATION_MANDATORY

当前如果有事务,Spring就会使用该事务;

否则会抛出异常

TransactionDefinition. PROPAGATION_REQUIRES_NEW

Spring总是开始一个新事务。如果当

前有事务,则该事务挂起

TransactionDefinition. PROPAGATION_NOT_SUPPORTED

Spring不会执行事务中的代码。代码总

是在非事务环境下执行,如果当前

有事务,则该事务挂起

TransactionDefinition. 

PROPAGATION_NEVER

即使当前有事务,Spring也会在非

事务环境下执行。如果当前有事务,

则抛出异常

TransactionDefinition. 

PROPAGATION_NESTED

如果当前有事务,则在嵌套

事务中执行。如果没有,那么

执行情况

Transaction- Definition.

PROPAGATION_REQUIRED一样

 

 

16.2.2 使用TransactionStatus接口

如代码清单16-2所示,TransactionStatus接口可以让事务管理器控制事务的执行,可以检查事务是不是一个新事务,或者是否只读。TransactionStatus还可以初始化回滚操作。

代码清单16-2 TransactionStatus 声明

TransactionStatus接口中的方法很容易理解;最引人注目的就是setRollbackOnly(),它将一个事务标识为不可提交的。换句话说,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。在大多数情况下,事务管理器会检测到这一点,在它发现事务要提交时会立刻结束事务。代码清单16-3中的伪代码说明了这一点。

代码清单16-3 setRollbackOnly()方法的使用

TransactionDefinition接口_第1张图片

在调用完setRollbackOnly()后,大多数数据库可以继续执行下一条select语句,但不允许执行update语句--执行update是没有意义的,因为事务只可以进行读取操作,任何修改都不会被提交。

 

 

16.2.3 PlatformTransactionManager的实现

PlatformTransactionManager接口使用TransactionDefinition和TransactionStatus接口,创建并管理事务。该接口的实现必须对事务管理器有深入理解。DataSourceTransactionManager控制着从DataSource中获得的JDBC Connection上的事务的执行;HibernateTransactionManager控制着Hibernate session上的事务的执行;JdoTransactionManager管理着JDO事务;JtaTransactionManager将事务管理委托给JTA。

 

16.3 对一个事务管理示例的探索(1)

本章的第一部分已经对Spring中的事务基础架构进行了概览,但我们认为,仍然需要给出一个能说明如何使用Spring的事务支持的示例。

使用事务操作的方式有3种基本方式:可以使用声明式事务,只需声明某个方法需要事务就行了;可以使用源码级的元素据来说明某个方法需要一个事务;还可以用编写事务代码的方式来实现。Spring对这3种方式都提供了支持,我们从最灵活最方便的方式开始,即声明式事务管理。

首先我们将展示几种事务支持的实现方式。浏览一下图16-1中的UML类图,对该示例应用中需要保存的数据有一个直观印象。

尽管该类图看起来有些复杂,但我们只是实现一个简单的银行应用程序。我们有一个用来维护账户余额的Account类(这是真实银行账户的简化版,但对于示例来说足够用了)。我们将AccountIdentity作为银行账户的唯一标识。BalanceMutator接口只有一个mutate(BigDecimal)方法,我们在BankService- Support中实现该接口。CreditBalanceMutator将贷款数额加到了balance参数中。DebitBalanceMutator稍微有点复杂,它检查账户中是否有足够的钱可以借出。若想进一步探究这个概念,例如可以修改DebitBalanceMutator以允许透支。

AccountDao定义了一个数据访问接口,该接口由JdbcAccountDao类实现。接下来,我们在BankService接口中定义了transfer和getBalance方法。BankServiceSupport实现了这两个方法,它用两个以do开头的protected方法进行实现。我们将使用BankServiceSupport子类来演示各种不同的事务管理技术。

TransactionDefinition接口_第2张图片
(点击查看大图)图16-1 带有事务的银行应用示例的UML类图

非事务性代码

在讨论事务管理之前,我们得编写必要的支持代码。让我们以代码清单16-4中的SQL代码开始吧,这些代码创建了t_account表并插入几个测试账户。

代码清单16-4 样例账户应用的SQL 代码

TransactionDefinition接口_第3张图片

这些SQL代码没什么特别的。如果你没有使用Oracle 10g数据库,那么你可能需要修改一下SQL语法使之适合你的数据库。接下来,我们看看Account与AccountIdentity类及BalanceMutator接口。我们在代码清单16-5中列出了这几个类和接口的代码。

代码清单16-5 Account、AccountIdentity和BalanceMutator

TransactionDefinition接口_第4张图片

你可以看到Account类有一个我们赋予的识别器(Long id)。该识别器就是实现的细节问题了:我们的代码需要这个ID,但它对用户来说是没有任何意义的。用户使用账户号和分类号来标识其账户。Account类只有一个重要的方法:changeBalance(BalanceMutator)。这个方法使用BalanceMutator实例来更新账户的余额。

说明 我们选择使用BalanceMutator来更新账户的余额,因为我们觉得管理余额的规则可能会非常复杂。使用一个接口(该接口在服务层实现)会比在Account类中简单地定义credit(BigDecimal)和debit(BigDecimal)方法更灵活。

接下来,我们看看该示例应用的数据访问层。简单起见,我们使用SimpleJdbcTemplate(请查看第9章以了解关于Spring JDBC支持的详细内容)。我们采取了Spring应用所使用的一种典型方式:创建AccountDao接口及其实现--JdbcAccountDao。代码清单16-6列出了接口和实现的源代码。

代码清单16-6 AccountDao接口和JdbcAccountDao实现

TransactionDefinition接口_第5张图片
TransactionDefinition接口_第6张图片

我们尽量保持代码的简单性。记住我们并不是在展示Spring JDBC,而仅仅是实现数据访问层代码以说明Spring的事务管理。最后,我们实现了BankServiceSupport,将该类作为事务性的BankService实现的父类。这样,BankServiceSupport就用以do开头的protected方法去实现BankService中的方法。代码清单16-7显示了BankServiceSupport的实现。

代码清单16-7 BankServiceSupport代码

TransactionDefinition接口_第7张图片
TransactionDefinition接口_第8张图片
TransactionDefinition接口_第9张图片

转载于:https://www.cnblogs.com/fengchaowang/p/4122579.html

你可能感兴趣的:(TransactionDefinition接口)