Sun ONE logo     上一个      目录      索引      下一个     
Sun ONE Application Server 7, Update 1 管理员指南



使用事务服务

事务是商业运作的重要组成部分。典型的商业事务为两方或多方之间资产的转移。准确的记录通常存储在一个或多个数据库中。由于此信息对于商业运作十分关键,因此它必须有效、实时、可靠。对于编程新手来说,事务处理是比较困难的。J2EE 平台提供了多种抽象概念,用于简化可靠事务处理应用程序的开发。本章将讨论 J2EE 事务及 Sun ONE Application Server 中的事务支持。

本 module 概述了 Java 事务,并详述了 Sun ONE Application Server 中的事务支持。

本 module 包括以下主题:

什么叫事务?

要模拟商业事务,程序需要执行几个步骤。例如,通过执行以下伪代码中列出的步骤,财务程序可以将资金从支票帐户转到储蓄帐户中:

begin transaction

debit checking account

credit savings account

update history log

commit transaction

在以上伪代码中,begin 语句和 commit 语句标记出事务的界限。要完成此事务,必须完成以上三个步骤。否则,数据的完整性将被破坏。

该保证称为原子性。事务可以通过两种方式结束:使用 commitrollback。提交事务时,在事务边界内通过语句进行的修改将被永久保存。更改是可持续的,即可以在系统出现故障之前一直存在。如果事务内的语句出现故障,事务将回滚,撤销事务内已执行的所有语句的效果。例如,在伪代码中,如果磁盘驱动器在贷出过程中崩溃,事务将回滚并撤销借入语句所做的数据更改。

即使是事务失败,数据完整性也不会受到破坏,因为事务帐户仍然是平衡的。事务操作的这个特点称为事务一致性

事务服务还具有隔离的特点,也就是说提交或回滚事务之前其它应用程序和线程无法看到事务中进行的阶段。事务被提交后,应用程序和线程即可安全查看提交的事务。

J2EE 中的事务

J2EE 中的事务处理涉及以下五个实体:事务管理器、应用程序服务器、资源管理器、资源适配器和用户应用程序。通过实现不同的 API 和功能,每个实体都有助于实现事务处理过程的可靠性,如下所述:

  • 事务管理器提供支持事务划分、事务资源管理、同步和事务上下文传播所需的服务和管理功能。
  • 应用程序服务器提供了支持应用程序运行时环境(包括事务状态管理)所需的基础结构。
  • 应用程序可以使用资源管理器(通过资源适配器)访问资源。资源管理器通过实现事务管理器所使用的事务资源接口来参与分布式事务,从而与事务关联、事务完成及恢复工作进行通信。例如,关系型数据库服务器就是这样的资源管理器。
  • 资源适配器是一个系统级的软件库,应用程序服务器或客户机用它连接到资源管理器。资源适配器通常专用于资源管理器。它以库的形式存在,并在使用它的客户机地址空间中使用。例如,JDBC 驱动程序就是这样的资源适配器。
  • 为在 J2EE 应用程序服务器环境中运行而开发的事务用户应用程序可以使用 JNDI 查找事务数据源及事务管理器(可选)。可以使用 EJB 的声明事务属性设置或明确的程序事务划分。

术语“资源管理器”通常可以和“资源适配器”互用,因为这两个实体之间有着紧密的联系。

事务资源管理器

J2EE 事务支持下列事务资源管理器。

数据库

数据库是 J2EE 应用程序中最常见的事务资源管理器。JDBC 是 J2EE 组件用来访问数据库的 API。数据库资源被配置为 JDBC 资源。JDBC 资源由资源管理器或 JDBC 驱动程序来管理。JDBC 驱动程序支持本地事务或全局事务,在某些情况下可以同时支持这两种事务。

Sun ONE Application Server 支持在各种 J2EE 组件中使用 JDBC 和事务。有关注册和配置 JDBC 资源的详细信息,请参见“关于 JDBC 资源”。应用程序服务器负责提供事务的连续性(即启动事务和从多个应用程序组件访问数据库)。例如,servlet 可以启动事务、访问数据库、调用访问同一事务中同一数据库的企业 Bean,最后提交事务。

JMS 提供者

JMS 表示 Java 消息传送服务。在 J2EE 术语中,JMS 提供者就是指消息代理服务。JMS API 能够在应用程序之间提供可靠的事务消息交换。对 JMS 数据源的支持是 J2EE 中必需的功能。JMS 资源和 JDBC 资源可以参与同一事务。

Sun ONE Application Server 与 Sun ONE Message Queue 集成在一起,该软件是一个全功能 JMS 提供者和对应的事务资源管理器。Sun ONE Application Server 以这种方式从 servlet、JSP 页面和企业 Bean 中启用事务 JMS 访问。Sun ONE Application Server 也可以与第三方 JMS 提供者结合使用。有关详细信息,请参见“使用 JMS 服务”

J2EE 连接器

Sun ONE Application Server 支持将 XATransaction 模式用作事务资源管理器的资源适配器。平台必须启用从 servlet、JSP 页面和企业 Bean 对资源适配器的事务访问。也可以从一个事务的多个应用程序组件访问资源适配器。例如,servlet 可能希望启动事务、访问资源适配器、调用访问同一事务中的资源适配器的企业 Bean,最后提交事务。

本地和分布式事务

只涉及一种资源的事务可以使用本地事务来完成。本地事务还要求所有参与的应用程序组件都在一个进程中执行。涉及多种资源或多个参与者进程的事务则是分布式或全局事务。本地事务优化使用资源管理器的特定优化,这种优化对于 J2EE 应用程序是透明的。

事务类型主要由相关资源管理器实现的接口来确定。例如,实现 javax.sql.DataSource 接口的 JDBC 数据源可以参与本地事务。实现 javax.sql.XADataSource 的数据源可以参与全局事务。有些 JDBC 资源可以实现两个接口,并且当这类 JDBC 资源使用 Sun ONE Application Server 注册时,可能需要提供 Sun ONE Application Server 中的其它配置信息来表示该资源的首选功能。

本地事务较为简单,自然要比全局事务的效率高。但是,如果需要转换的数据分布在多个数据源,则本地事务不能满足需要。有时,无法预测一个事务中需要多少个数据源。因此,在现实世界中最常见的是全局事务。某些性能优化可能在全局事务中更有效。

J2EE 支持由用于访问事务中多个企业 Bean 的 servlet 或 JSP 的任意组合组成的事务应用程序。每个组件都需要一个或多个连接来访问一个或多个事务资源管理器。在下图中,调用树从访问多个企业 Bean 的 servlet 或 JSP 页面启动,然后再访问其它企业 Bean。这些组件通过连接访问资源管理器。

事务中访问资源的 J2EE 组件
图中的调用树显示了一个事务的所有组件。

例如,应用程序可能要求上图中的所有组件都访问一个事务中的资源。应用程序服务器提供者必须提供支持这种方案的事务功能。

J2EE 事务管理支持平面事务。平面事务不能包含子(嵌套)事务。

事务恢复是分布式事务的重要方面。在重要的阶段无法访问资源或出现其它不可恢复的错误时,则需要考虑分布式事务的状态。自动或手动恢复出现问题或未完成的事务时是 Sun ONE Application Server 的重要功能。可以使用管理界面启用自动事务恢复。有关如何控制事务恢复的详细信息,请参见“事务服务管理”

连接(此处用作资源的同意词)可以被标记为可共享或不可共享。准备以不可共享方式使用连接的 J2EE 应用程序组件必须提供有关连接不可共享的部署信息,以防容器共享连接。例如,改变安全属性、隔离级别、字符设置和本地化配置时可能需要此部署信息。

容器不能尝试共享标记为不可共享的连接。如果连接未标记为不可共享,则不管连接是否共享,该连接对于应用程序来说必须是透明的。

J2EE 应用程序组件可以使用可选的部署描述符元素 res-sharing-scope 来表示与资源管理器的连接是否可共享。如果没有部署提示,则容器应假设连接是可共享的。J2EE 应用程序组件可以高速缓存连接对象,并在多重事务中重复使用这些对象。提供连接共享的容器应该能够透明地交换高速缓存连接对象(分发时),以便在正确的事务范围内指向适当的共享连接。

当设计企业 Bean 应用程序时,开发者必须确定如何指定边界。

容器管理的事务

在包含容器管理事务的企业 Bean 中,EJB 容器可以设置事务的边界。可以通过任意类型的企业 Bean 使用容器管理事务:会话、实体或消息驱动。容器管理的事务可以简化开发过程,因为企业 Bean 代码不能明确地标记事务的边界。代码不包括开始和结束事务的语句。

通常,企业 Bean 方法开始之前,容器会立即启动一个事务,并在方法即将退出之前提交事务。每种方法都可以与单个事务相关联。一个方法内不允许包含嵌套事务或多个事务。

容器管理事务不要求所有方法都与事务相关联。部署 Bean 时,可以通过设置事务属性来指定与事务相关联的 Bean 方法。

本节包括以下主题:

事务属性

事务属性用于控制事务的范围。下图说明了控制事务范围的重要性。在以下图表中,method-A 启动了一个事务,然后调用 Bean-2 的 method-B。执行 method-B 时,它是在由 method-A 启动的事务范围内运行还是执行新的事务?答案取决于 method-B 的事务属性。

  
图中显示了事务的范围。
事务属性

事务的属性值可以为以下值之一:

Required

如果客户机在事务内运行并调用企业 Bean 的方法,则方法在客户机的事务内执行。如果客户机与事务不关联,容器将在运行方法之前启动新事务。

Required 属性适用于大多数事务。因此,您可能需要将其用作默认属性,至少在开发初期希望如此。由于事务属性是声明性的,因此以后可以很方便地进行更改。

RequiresNew

如果客户机在事务内运行并调用企业 Bean 的方法,容器将执行以下步骤:

  • 挂起客户机的事务
  • 启动新事务
  • 将调用委托给方法
  • 方法完成后恢复客户机事务

如果客户机与事务不关联,容器将在运行方法之前启动新事务。

如果希望确保方法始终在新事务中运行,则应该使用 RequiresNew 属性。

Mandatory

如果客户机在事务内运行并调用企业 Bean 的方法,则方法在客户机的事务内执行。如果客户机与事务不关联,容器将抛出 TransactionRequiredException

如果企业 Bean 的方法必须使用客户机的事务,则可以使用 Mandatory 属性。

NotSupported

如果客户机在事务内运行并调用企业 Bean 的方法,则容器将在调用方法之前挂起客户机的事务。方法完成后,容器将恢复客户机的事务。

如果客户机与事务不关联,运行方法之前,容器不会启动新事务。

为不需要事务的方法使用 NotSupported 属性。由于事务会占用系统资源,因此该属性可以改善性能。

Supports

如果客户机在事务内运行并调用企业 Bean 的方法,则方法在客户机的事务内执行。如果客户机与事务不关联,运行方法之前,容器不会启动新事务。

由于方法的事务操作可能各不相同,因此应该谨慎使用 Supports 属性。

Never

如果客户机在事务内运行并调用企业 Bean 方法,容器将抛出 RemoteException。如果客户机与事务不关联,运行方法之前,容器不会启动新事务。

属性小结

下表总结了事务属性的效果。T1 和 T2 事务都由容器来控制。T1 事务与企业 Bean 中调用方法的客户机关联。大多数情况下,客户机是另一种企业 Bean。而 T2 事务仅在方法执行前由容器来启动。

在最后一列,“None”表示在由容器控制的事务中不执行商业方法。但是,这种商业方法中的数据库调用可以由 DBMS 的事务管理器来控制。

   事务属性

事务属性

 

客户机事务

 

商业方法的事务

 

Required

 

T2

 

T1

 

T1

 

RequiresNew

 

T2

 

T1

 

T2

 

Mandatory

 

错误

 

T1

 

T1

 

NotSupported

 

 

T1

 

 

Supports

 

T1

 

T1

 

设置事务属性

由于事务属性存储在部署描述符中,因此,在 J2EE 应用程序部署的很多阶段中都可以对其进行更改:企业 Bean 的创建阶段、应用程序汇编阶段以及部署阶段。但是,开发者需要在创建 Bean 时指定属性。只有将组件组合为大型应用程序的应用程序开发者才能修改这些属性,部署 J2EE 应用程序的用户不负责指定应用程序属性。

可以为整个企业 Bean 或单个方法指定事务属性。如果为某一方法指定了一个属性,而为 Bean 指定了另一个属性,则方法的属性优先。为单个方法指定属性时,要求会因 Bean 的类型不同而异。会话 Bean 需要定义的属性用于商业方法,而不允许将这些属性用于创建方法。实体 Bean 要求事务属性用于商业、创建、删除和查找器方法。消息驱动 Bean 要求事务属性(Required 属性或 NotSupported 属性)用于 onMessage 方法。

回滚容器管理的事务

回滚容器管理的事务有两种方法。第一种方法是:如果抛出系统异常,容器将自动回滚事务。第二种方法是:通过调用 EJBContext 接口的 setRollbackOnly 方法,Bean 方法将指示容器回滚事务。如果 Bean 抛出一个应用程序异常,回滚则不是自动的,但可以通过调用 setRollbackOnly 启动。

在以下示例中,BankEJB 示例的 transferToSaving 方法说明了 setRollbackOnly 方法。如果发生负检查平衡,transferToSaving 将调用 setRollBackOnly,并抛出应用程序异常 (InsufficientBalanceException)。updateCheckingupdateSaving 方法将更新数据库表。如果更新失败,这些方法将抛出 SQLExceptiontransferToSaving 方法将抛出 EJBException。由于 EJBException 是一个系统异常,因此会引起容器自动回滚事务。以下是 transferToSaving 方法的代码:

public void transferToSaving(double amount) throws
InsufficientBalanceException {

checkingBalance -= amount;
savingBalance += amount;

if (checkingBalance < 0.00) {
context.setRollbackOnly();

throw new InsufficientBalanceException();
}
try {
updateChecking(checkingBalance);

updateSaving(savingBalance);
} catch (SQLException ex) {
throw new EJBException
("Transaction failed due to SQLException: "
+ ex.getMessage());
}
}

当容器回滚事务时,通常会撤销事务内由 SQL 调用对数据所做的更改。然而,只有在实体 Bean 中,容器才撤销对实例变量所做的更改。(通过自动调用实体 Bean 的 ejbLoad 方法可以完成此操作,即从数据库加载实例变量。)发生回滚时,会话 Bean 必须明确地重置事务中已更改的实例变量。要重置会话 Bean 的实例变量,最简单的方法是实现 SessionSynchronization 接口。

还可以通过将事务 ID 传递给命令行界面来回滚事务。有关详细信息,请参见“使用命令行界面管理事务”

同步会话 Bean 的实例变量

通过 SessionSynchronization 接口(可选)可以同步数据库中的实例变量及其相应的值。在事务的各主要阶段,容器将调用 SessionSynchronization 方法(afterBeginbeforeCompletionafterCompletion)。

afterBegin 方法通知实例新的事务已开始。容器首先调用 afterBegin,然后调用事务内的第一个商业方法。afterBegin 方法适用于从数据库加载实例变量。例如,BankBean 类可以在 afterBegin 方法中加载 checkingBalancesavingBalance 变量。

public void afterBegin() {

System.out.println("afterBegin()");
try {
checkingBalance = selectChecking();
savingBalance = selectSaving();
} catch (SQLException ex) {
throw new EJBException("afterBegin Exception: " +
ex.getMessage());
}
}

商业方法完成后,容器将调用 beforeCompletion 方法,但仅在提交前调用。beforeCompletion 方法是会话 Bean 回滚事务的最后一种方法(通过调用 setRollbackOnly)。如果尚未使用实例变量的值更新数据库,会话 Bean 则可以在 beforeCompletion 方法中完成该操作。

afterCompletion 方法表示事务已完成。它是一个单布尔参数。如果事务被提交,其值为 True;如果事务被回滚,其值则为 False。如果发生回滚,会话 Bean 可以在 afterCompletion 方法中刷新数据库的实例变量:

public void afterCompletion(boolean committed) {

System.out.println("afterCompletion:" + committed);
if (committed == false) {
try {
checkingBalance = selectChecking();
savingBalance = selectSaving();
} catch (SQLException ex) {
throw new EJBException("afterCompletion SQLException:
" + ex.getMessage());
}
}
}

容器管理事务中不允许的方法

不要调用可能影响容器设定的事务边界的任何方法。以下是禁用的方法的列表:

  • java.sql.Connection 的提交方法和 setAutoCommit 和回滚方法
  • javax.ejb.EJBContextgetUserTransaction 方法
  • javax.transaction.UserTransaction 的方法

但是,可以使用这些方法设置 Bean 管理的事务中的边界。

Bean 管理的事务

在 Bean 管理的事务中,会话 Bean 或消息驱动的 Bean 中的代码明确地标出了事务的边界。实体 Bean 不能包含 Bean 管理的事务,而必须使用容器管理的事务。尽管带有容器管理事务的 Bean 需要较少的编码,但它也有一个不足之处:执行方法时,它可以仅与一个事务相关联,也可以与事务根本不相关联。如果此限制增加了编写代码的难度,则应该考虑使用 Bean 管理的事务。

以下伪代码说明了可以通过 Bean 管理的事务获得的精密控制的类型。通过检查各种条件,伪代码可以确定启动或停止商业方法中的各种事务。

begin transaction
...
update table-a
...
if (condition-x)
commit transaction
else if (condition-y)
update table-b
commit transaction
else
rollback transaction
begin transaction
update table-c
commit transaction

事务服务管理

可以通过使用管理界面或命令行界面来管理事务。

本节包括以下主题:

使用管理界面管理事务

可以使用管理界面启用监视、设置日志级别并指定事务的高级选项。

可以控制实例范围的事务服务属性,例如恢复方针和超时。此处指定的属性和配置存储在 server.xml 文件中。

要配置事务服务选项,请执行以下任务:

  1. 在管理界面的左侧窗格中,打开要修改其事务配置的 Sun ONE Application Server 实例树。
  2. 从显示的 J2EE 服务列表中选择事务服务。将看到以下窗口,如管理界面的右侧窗格中“配置事务服务选项”图中所示:

   配置事务服务选项
图中展示了 Java 事务服务的可配置高级服务选项。

  1. 要启用对事务的监视,请选中“Monitoring Enabled”复选框。下表列出了可以被监视的 Java 事务服务的功能:
  2.    Java 事务服务的可监视属性

    属性

     

    类型

     

    说明

     

    transactionsCompleted

     

    int

     

    启用监视后完成的事务数量

     

    transactionsRolledBack

     

    int

     

    启用监视后回滚的事务数量

     

    transactionsRecovered

     

    int

     

    启用监视后恢复的事务数量

     

    transactionsInFlight

     

    int

     

    当前正在处理的事务数量

     

    timeStamp

     

    long

     

    在生成统计的位置记录的时间(以毫秒为单位)。它记录 System.getCurrentTimeInMillis() 报告的所有内容。

     

  3. 从“Log Level”下拉列表中选择要为事务设置的日志级别。有关日志级别以及如何使用它们的详细信息,请参见“使用日志”
  4. 选中“Recover on Restart”旁边的复选框,以便在服务器重新启动时自动恢复失败的事务。在重要阶段无法访问资源或出现其它不可恢复的错误时,事务将无法完成,仍然保留在事务日志文件中。如果选中了此复选框,服务器将在重新启动服务器时尝试恢复出现问题的事务。如果相关资源仍然不可用,则会延迟服务器的重新启动。默认情况下不选中此复选框。
  5. 对于使用容器管理事务的企业 Bean,则可以通过设置“Transaction Timeout (secs)”属性来控制事务超时间隔。
  6. 如果该属性的值设置为 0,事务将不会超时。

    在“Transaction Timeout (secs)”字段中,指定事务超时间隔。如果在指定时间内未完成,事务将回滚。如果为此属性设置的值为 0,事务则不会超时。

  7. 在“Transaction Log Location”字段中,指定要存储日志文件的目录的绝对路径。要使新的事务日志目录生效,需要重新启动服务器。
  8. 从“Heuristic Decision”下拉框中,选择要应用到事务中的试探性决定。如果不能明确确定结果,请从指定的选项中选择“Commit”或“Rollback”,指定应用程序服务器应该在恢复期间确定的事务的结果。如果将“Heuristic Decision”设置为“Rollback”,将回滚事务。在某些情况下,提交这些事务更为合适。
  9. 在“Keypoint Interval (transactions)”字段中指定日志中密钥点操作之间的事务数量。通过删除已完成的事务和正在压缩文件的项,密钥点操作可以减小事务日志文件的大小。属性值越大,事务日志文件也越大,但同时密钥点操作更少,性能可能更佳。属性值越小(例如,100),日志文件也越小,而同时由于密钥点操作较为频繁,性能会略微降低。

使用命令行界面管理事务

可以使用命令行界面 (CLI) 管理并监视数据库事务,如以下各节中所述:

以下各节讲述了如何使用命令行界面管理和监视事务。

列出进行中的事务

应使用以下命令获取正在处理的事务数据(假设处于多模式,并且已经设置了用户名和密码):

- asadmin> get --monitor <instanceName>.transaction-service.inflight-tx

多行输出结果为:

Transaction Id State Elapsed Time (ms)

txnid1 Prepared 20

txnid2 Active 100

txnid3 Active 120

... ... ...

管理事务

列出进行中的事务中给出的示例中,假设您要使用以下事务 ID 回滚事务:txn-idstxnid2txnid3。回滚选定事务的样例命令如下:

asadmin> set --monitor <instanceName>.transaction-service.rollback-list=txnid2,txnid3

冻结事务服务

要冻结事务服务,请运行以下命令:

asadmin> set --monitor <instanceName>.transaction-service.freeze=true

当冻结事务服务后,应用程序服务器中的事务管理器将挂起所有进行中的事务。建议不要在生产部署系统中冻结事务。

要解冻事务服务,请运行以下命令:

asadmin> set --monitor <instanceName>.transaction-service.freeze=false

当重新设置事务服务时,系统将从停止点继续运行。如果活动系统处于冻结状态的时间太长,某些数据库连接则可能会超时,而导致事务回滚。

监视事务

要监视事务的数据(包括进行中的事务数据),请运行以下命令:

asadmin> get --monitor <instanceName>.transaction-service.*

如果运行此命令时没有处于活动状态的事务,将获得以下输出结果:

total-tx-completed = 5

total-tx-rolledback = 2

total-tx-inflight = 0

isFrozen = false

tx-inflight = No active transactions found.

如果运行此命令时有处于活动状态的事务,将获得以下输出结果:

total-tx-completed = 5

total-tx-rolledback = 2

total-tx-inflight = 2

isFrozen = false

tx-inflight =

Transaction Id State Elapsed Time(ms)

txnid1 Prepared 500

txnid2 Active 360


上一个      目录      索引      下一个     
Copyright 2003 Sun Microsystems, Inc. All rights reserved.