zoukankan      html  css  js  c++  java
  • 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()方法的使用

    在调用完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子类来演示各种不同的事务管理技术。

    (点击查看大图)图16-1 带有事务的银行应用示例的UML类图

    非事务性代码

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

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

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

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

    你可以看到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实现

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

    代码清单16-7 BankServiceSupport代码

  • 相关阅读:
    OnSharedPreferenceChangeListener不被调用原理及解决方案
    自测题的整理(持续更新)
    排序的练习题
    C++各种类型的简单排序大汇总~
    洛谷P1540 机器翻译
    队列
    文件和结构体
    洛谷P1079 Vigenère 密码
    洛谷P1328生活大爆炸版石头剪刀布
    洛谷P1553数字反转升级版
  • 原文地址:https://www.cnblogs.com/fengchaowang/p/4122579.html
Copyright © 2011-2022 走看看