编程的模式

来源:互联网 发布:淘宝大促官方论坛 编辑:程序博客网 时间:2024/05/17 22:50

J2EE 开发人员使用数据访问对象(Data Access Object DAO)设计模式,以便将低级别的数据访问逻辑与高级别的业务逻辑分离。实现 DAO 模式涉及比编写数据访问代码更多的内容。在本文中,Java 开发人员 Sean C. Sullivan 讨论了 DAO 编程中三个常常被忽略的方面:事务界定、异常处理和日志记录。
在过去 18 个月中,我参加了一个由有才华的软件工程师组成的小组,构建定制的、基于 Web 的供应链管理应用程序。我们的应用程序访问范围广泛的持久性数据,包括配送状态、供应链衡量(metrics)、库存、货运发票、项目管理数据和用户信息。我们用 JDBC API 连接到我们公司的不同数据库平台上,并在整个应用程序中使用 DAO 设计模式。

图 1 显示了应用程序和数据源之间的关系:

图 1. 应用程序和数据源


在整个应用程序中使用数据访问对象(DAO)使我们可以将底层数据访问逻辑与业务逻辑分离开来。我们构建了为每一个数据源提供 GRUD (创建、读取、更新、删除)操作的 DAO 类。

在本文中,我将为您介绍构建更好的 DAO 类的 DAO 实现策略和技术。更确切地说,我将讨论日志、异常处理和事务界定。您将学到如何将这三者结合到自己的 DAO 类中。本文假定您熟悉 JDBC API、SQL 和关系数据库编程。

我们将以对 DAO 设计模式和数据访问对象的概述开始。

DAO 基础
DAO 模式是标准 J2EE 设计模式之一。开发人员用这种模式将底层数据访问操作与高层业务逻辑分离开。一个典型的 DAO 实现有以下组件:

一个 DAO 工厂类
一个 DAO 接口
一个实现了 DAO 接口的具体类
数据传输对象(有时称为值对象)
具体的 DAO 类包含访问特定数据源的数据的逻辑。在下面一节中您将学习设计和实现数据访问对象的技术。有关 DAO 设计模式的更多内容请参阅 参考资料。

事务界定
关于 DAO 要记住的重要一点是它们是事务性对象。由 DAO 所执行的每一个操作 -- 如创建、更新或者删除数据 -- 都与一个事务相关联。因此,事务界定的概念就变得特别重要了。

事务界定是定义事务边界的方式。J2EE 规范描述了两种事务界定的模型:编程式(programmatic)和声明式(declarative)。表 1 分析了这两种模型:

表 1. 两种事务界定的模型 声明式事务界定 编程式事务界定
程序员用 EJB 部署描述符声明事务属性。 程序员负责编写事务逻辑。
运行时环境(EJB 容器)用这些属性自动管理事务。 应用程序通过一个 API 控制事务。


我们将侧重于编程式事务界定。

设计考虑
如前所述,DAO 是事务性对象。一个典型的 DAO 执行像创建、更新和删除这样的事务性操作。在设计 DAO 时,首先要问自己以下问题:

事务要如何开始?
事务应如何结束?
哪一个对象将负责开始一个事务?
哪一个对象将负责结束一个事务?
DAO 是否要负责事务的开始和结束?
应用程序是否需要通过多个 DAO 访问数据?
事务涉及到一个 DAO 还是多个 DAO?
一个 DAO 是否调用另一个 DAO 的方法?
了解上述问题的答案将有助于您选择最适合的 DAO 的事务界定策略。在 DAO 中有两种主要的界定事务的策略。一种方式是让 DAO 负责界定事务,另一种将事务界定交给调用这个 DAO 方法的对象处理。如果选择了前一种方式,那么就将事务代码嵌入到 DAO 中。如果选择后一种方式,那么事务界定代码就是在 DAO 类外面。我们将使用简单的代码示例帮助您更好理解每一种方式是如何工作的。

清单 1 显示了一个有两种数据操作的 DAO:创建和更新:

清单 1. DAO 方法

public void createWarehouseProfile(WHProfile profile);
public void updateWarehouseStatus(WHIdentifier id, StatusInfo status);



清单 2 显示了一个简单的事务。事务界定在 DAO 类外面。注意在这个例子中调用者是如何在一个事务中结合多个 DAO 操作的。

清单 2. 调用者管理的事务

tx.begin(); // start the transaction
dao.createWarehouseProfile(profile);
dao.updateWarehouseStatus(id1, status1);
dao.updateWarehouseStatus(id2, status2);
tx.commit(); // end the transaction



这种事务界定策略对于需要在一个事务中访问多个 DAO 的应用程序特别有用。

可以用 JDBC API 或者 Java 事务 API(Java Transaction API JTA)实现事务界定。 JDBC 事务界定比 JTA 事务界定要简单,但是 JTA 提供了更多的灵活性。在下面一节中我将更深入地分析事务界定的机制。

用 JDBC 进行事务界定
JDBC 事务是用 Connection 对象控制的。JDBC Connection 接口(java.sql.Connection)提供了两种事务模式:自动提交和手工提交。java.sql.Connection 提供了以下控制事务的方法:

public void setAutoCommit(boolean)
public boolean getAutoCommit()
public void commit()
public void rollback()
清单 3 显示了如何用 JDBC API 界定一个事务:

清单 3. 用 JDBC API 进行事务界定

import java.sql.*;
import javax.sql.*;

// ...
DataSource ds = obtainDataSource();
Connection conn = ds.getConnection();
conn.setAutoCommit(false);
// ...
pstmt = conn.prepareStatement("UPDATE MOVIES ...");
pstmt.setString(1, "The Great Escape");
pstmt.executeUpdate();
// ...
conn.commit();
// ...



使用 JDBC 事务界定时,您可以将多个 SQL 语句结合到一个事务中。JDBC 事务的一个缺点是事务的范围局限于一个数据库连接。一个 JDBC 事务不能跨越多个数据库。在下面,我们将看一下如何用 JTA 进行事务界定。因为 JTA 不像 JDBC 那样有名,所以我们首先做一个简介。

JTA 简介
Java 事务 API(JTA) 及其同门兄弟 Java 事务服务(Java Transaction Service JTS)为 J2EE 平台提供了分布式事务服务。一个分布式的事务涉及一个事务管理器和一个或者多个资源管理器。一个资源管理器是任何类型的持久性的数据存储。事务管理器负责协调所有事务参与者之间的通信。事务管理器与资源管理器之间的关系如图 2 所示:

图 2. 一个事务管理器和资源管理器


JTA 事务比 JDBC 事务功能更强。JDBC 事务局限为一个数据库连接,而 JTA 事务可以有多个参与者。所有下列 Java 平台组件都可以参与 JTA 事务:

JDBC 连接
JDO PersistenceManager 对象
JMS 队列
JMS 主题
企业 JavaBeans
符合 J2EE 连接体系结构(J2EE Connector Architecture)规范的资源适配器
使用 JTA 的事务界定
要用 JTA 进行事务界定,应用程序要调用 javax.transaction.UserTransaction 接口中的方法。清单 4 显示了对 UserTransaction 对象的典型 JNDI 查询:

清单 4. 一个对 UserTransaction 对象的 JDNI 查询


import javax.transaction.*;
import javax.naming.*;
// ...
InitialContext ctx = new InitialContext();
Object txObj = ctx.lookup("java:comp/UserTransaction");
UserTransaction utx = (UserTransaction) txObj;




当应用程序找到了 UserTransaction 对象后,就可以开始事务了,如清单 5 所示:

清单 5. 用 JTA 开始一个事务


utx.begin();
// ...
DataSource ds = obtainXADataSource();
Connection conn = ds.getConnection();
pstmt = conn.prepareStatement("UPDATE MOVIES ...");
pstmt.setString(1, "Spinal Tap");
pstmt.executeUpdate();
// ...
utx.commit();
// ...




当应用程序调用 commit()时,事务管理器用一个两阶段的提交协议结束事务。

控制事务的 JTA 方法
javax.transaction.UserTransaction 接口提供了以下事务控制方法:

public void begin()
public void commit()
public void rollback()
public int getStatus()
public void setRollbackOnly()
public void setTransactionTimeout(int)
应用程序调用 begin() 开始事务。应用程序调用 commit() 或者 rollback() 结束事务。参阅参考资料以了解更多关于用 JTA 进行事务管理的内容。

使用 JTA 和 JDBC
开发人员通常在 DAO 类中用 JDBC 进行底层数据操作。如果计划用 JTA 界定事务,那么就需要有一个实现 javax.sql.XADataSource、javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驱动程序。一个实现了这些接口的驱动程序将可以参与 JTA 事务。一个 XADataSource 对象就是一个 XAConnection 对象的工厂。XAConnections 是参与 JTA 事务的 JDBC 连接。

您将需要用应用服务器的管理工具设置 XADataSource。从应用服务器和 JDBC 驱动程序的文档中可以了解到相关的指导。

J2EE 应用程序用 JNDI 查询数据源。一旦应用程序找到了数据源对象,它就调用 javax.sql.DataSource.getConnection() 以获得到数据库的连接。

XA 连接与非 XA 连接不同。一定要记住 XA 连接参与了 JTA 事务。这意味着 XA 连接不支持 JDBC 的自动提交功能。同时,应用程序一定不要对 XA 连接调用 java.sql.Connection.commit() 或者 java.sql.Connection.rollback()。相反,应用程序应该使用 UserTransaction.begin()、UserTransaction.commit() 和 serTransaction.rollback()。

选择最好的方式
我们讨论了如何用 JDBC 和 JTA 界定事务。每一种方式都有其优点,您需要决定哪一种最适合于您的应用程序。

在最近的许多项目中,我们小组是用 JDBC API 进事务界定来构建 DAO 类的。这些 DAO 类可以总结如下:

事务界定代码嵌入在 DAO 类中。
DAO 类使用 JDBC API 进行事务界定。
调用者不能界定事务。
事务范围局限于单个 JDBC 连接。
JDBC 事务并不总是适合复杂的企业应用程序。如果您的事务要跨越多个 DAO 或者多个数据库,那么下列实现策略也许更合适:

事务用 JTA 界定。
事务界定代码从 DAO 中分离出来。
调用者负责界定事务。
DAO 加入一个全局事务。
JDBC 方式由于其简单性而具有吸引力,JTA 方式提供了更大的灵活性。您所选择的实现将取决于应用程序的特定需求。

日志记录和 DAO
一个良好实现的 DAO 类将使用日志记录来捕捉有关其运行时行为的细节。您可以选择记录异常、配置信息、连接状态、JDBC 驱动程序元数据、或者查询参数。日志对于开发的所有阶段都很有用。我经常在开发时、测试时和生产中分析应用程序日志。

在本节,我将展示一个显示如何将 Jakarta Commons Logging 加入到 DAO 中的代码示例。在这之前,让我们回顾一下一些基本知识。

选择日志库
许多开发人员使用一种原始格式进行日志记录:System.out.println 和 System.err.println。Println 语句速度快且使用方便,但是它们没有提供全功能的日志记录系统所具有的功能。表 2 列出了 Java 平台的日志库:

表 2. Java 平台的日志库 日志库 开放源代码? URL
java.util.logging 不是
http://java.sun.com/j2se/
Jakarta Log4j 是
http://jakarta.apache.org/log4j/
Jakarta Commons Logging 是
http://jakarta.apache.org/commons/logging.html


java.util.logging 是 J2SE 1.4 平台上的标准 API。不过,大多数开发人员同意 Jakarta Log4j 提供了更多的功能和更大的灵活性。Log4j 优于 java.util.logging 的一点是它同时支持 J2SE 1.3 和 J2SE 1.4 平台。

Jakarta Commons Logging 可以与 java.util.logging 或者 Jakarta Log4j 一同使用。Commons Logging 是一个日志抽象层,它隔离了应用程序与底层日志实现。使用 Commons Logging,您可以通过改变配置文件更换底层日志实现。Commons Logging 在 Jakarta Struts 1.1 和 Jakarta HttpClient 2.0 中使用。

一个日志记录示例
清单 7 显示了如何在 DAO 类中使用 Jakarta Commons Logging:

清单 7. DAO 类中的 Jakarta Commons Logging

import org.apache.commons.logging.*;

class DocumentDAOImpl implements DocumentDAO
{
static private final Log log = LogFactory.getLog(DocumentDAOImpl.class);

public void deleteDocument(String id)
{
// ...
log.debug("deleting document: " + id);
// ...
try
{
// ... data operations ...
}
catch (SomeException ex)
{
log.error("Unable to delete document", ex);
// ... handle the exception ...
}
}
}



日志记录是所有任务关键型应用程序的重要部分。如果在 DAO 中遇到故障,那么日志通常可以提供判断出错位置的最好信息。将日志加入到 DAO 可以保证您有机会进行调试和故障排除。

DAO 中的异常处理
我们讨论过了事务界定和日志,现在对于如何在数据访问对象上应用它们有了更深入的理解。我们的第三个和最后一个讨论议题是异常处理。遵从几个简单的异常处理指导可以使您的 DAO 更容易使用、更健壮及更易于维护。

在实现 DAO 模式时,考虑以下问题:

DAO 的公共接口中的方法是否抛出检查过的异常?
如果是的话,抛出何种检查过的异常?
在 DAO 实现类中如何处理异常?
在使用 DAO 模式的过程中,我们的小组开发了一些处理异常的原则。遵从这些原则可以极大地改进您的 DAO:

DAO 方法应该抛出有意义的异常。


DAO 方法不应该抛出 java.lang.Exception。java.lang.Exception 太一般化了。它不传递关于底层问题的任何信息。


DAO 方法不应该抛出 java.sql.SQLException。SQLException 是一个低级别的 JDBC 异常。一个 DAO 应该力争封装 JDBC 而不是将 JDBC 公开给应用程序的其余部分。


只有在可以合理地预期调用者可以处理异常时,DAO 接口中的方法才应该抛出检查过的异常。如果调用者不能以有意义的方式处理这个异常,那么考虑抛出一个未检查的(运行时)异常。


如果数据访问代码捕获了一个异常,不要忽略它。忽略捕获的异常的 DAO 是很难进行故障诊断的。


使用链接的异常将低级别的异常转化为高级别的异常。


考虑定义标准 DAO 异常类。Spring Framework (参阅参考资料)提供了很好的一套预定义的 DAO 异常类。
有关异常和异常处理技术的更多信息参阅参考资料。

实现实例: MovieDAO
MovieDAO 是一个展示本文中讨论的所有技术的 DAO:事务界定、日志和异常处理。您可以在参考资料一节中找到 MovieDAO 源代码。代码分为三个包:

daoexamples.exception
daoexamples.movie
daoexamples.moviedemo
DAO 模式的这个实现包含下面列出的类和接口:

daoexamples.movie.MovieDAOFactory
daoexamples.movie.MovieDAO
daoexamples.movie.MovieDAOImpl
daoexamples.movie.MovieDAOImplJTA
daoexamples.movie.Movie
daoexamples.movie.MovieImpl
daoexamples.movie.MovieNotFoundException
daoexamples.movie.MovieUtil
MovieDAO 接口定义了 DAO 的数据操作。这个接口有五个方法,如下所示:

public Movie findMovieById(String id)
public java.util.Collection findMoviesByYear(String year)
public void deleteMovie(String id)
public Movie createMovie(String rating, String year, String, title)
public void updateMovie(String id, String rating, String year, String title)
daoexamples.movie 包包含 MovieDAO 接口的两个实现。每一个实现使用一种不同的方式进行事务界定,如表 3 所示:

表 3. MovieDAO 实现 MovieDAOImpl MovieDAOImplJTA
实现 MovieDAO 接口? 是 是
通过 JNDI 获得 DataSource? 是 是
从 DataSource 获得 java.sql.Connection 对象? 是 是
DAO 在内部界定事务? 是 否
使用 JDBC 事务? 是 否
使用一个 XA DataSource? 否 是
参与 JTA 事务? 否 是


MovieDAO 演示应用程序
这个演示应用程序是一个名为 daoexamples.moviedemo.DemoServlet 的 servlet 类。DemoServlet 使用这两个 Movie DAO 查询和更新表中的电影数据。

这个 servlet 展示了如何将支持 JTA 的 MovieDAO 和 Java 消息服务(Java Message Service)结合到一个事务中,如清单 8 所示。

清单 8. 将 MovieDAO 和 JMS 代码结合到一个事务中

UserTransaction utx = MovieUtil.getUserTransaction();
utx.begin();
batman = dao.createMovie("R",
"2008",
"Batman Reloaded");
publisher = new MessagePublisher();
publisher.publishTextMessage("I'll be back");
dao.updateMovie(topgun.getId(),
"PG-13",
topgun.getReleaseYear(),
topgun.getTitle());
dao.deleteMovie(legallyblonde.getId());
utx.commit();



要运行这个演示应用程序,需要在应用服务器上配置一个 XA 数据源和一个非 XA 数据源。然后,部署 daoexamples.ear 文件。这个应用程序可以在任何兼容 J2EE 1.3 的应用服务器上运行。参阅参考资料以获得 EAR 文件和源代码。

结束语
正如本文所展示的,实现 DAO 模式需要做比编写低级别的数据访问代码更多的工作。现在,通过选择一个适合您的应用程序的事务界定策略、通过在 DAO 类中加入日志记录,以及通过遵从几项简单的异常处理原则,您可以构建更好的 DAO。

参考资料

从 daoexamples.sourceforge.net上下载 MovieDAO 源代码。


想要学习有关数据访问对象模式的更多内容?可以从核心 J2EE 模式主页开始。


Kyle Brown 的“A stepped approach to J2EE testing with SDAO”(developerWorks,2003 年 3 月)提供了对数据访问对象和 DAO 设计模式的简要介绍。


Dragonslayer 的教程“Create persistent application data with Java Data Objects”(developerWorks,2003 年 7 月)向您展示了如何结合 Struts 与 DAO 模式以用于影响小的企业数据持久性。


Srikanth Shenoy 的“EJB 异常处理的最佳做法”(developerWorks,2002 年 5 月)介绍了异常处理基础和使用 Log4J 进行日志记录。


Java 理论与实践系列从“理解 JTS -- 事务处理简介”开始(developerWorks,2002年3月)提供了对 Java 事务 API 的三部分介绍。


Java Transaction API 是 J2EE 平台的关键部分。


Jakarta Log4j 是 Java 应用程序的世界级日志库。


Jakarta Commons Logging 提供了容易使用的日志抽象层。


Spring Framework 为 JDBC 和事务管理提供了抽象层。此外,这个框架包含标准的 DAO 异常类和 JNDI 帮助器类。


JDBC事务对复杂的企业应用程序不总是有效的。如果你的事务将跨越多个DAO对象或
多个数据库,那么下面的实现策略可能会更恰当。:
.用JTA对事务进行划分
.事务划分代码被DAO分开
.调用者承担划分事务的责任
.DAO参与一个全局的事务中

JDBC方法由于它的简易性而具有吸引力,JTA方法提供了更多灵活性。你选择什么样的实现将依赖于你的应用程序的特定需求。

日志记录和DAO
一个好的DAO实现类将使用日志记录来捕获有关它在运行时的行为细节。你可以选择记录异常、配置信息、连接状态、JDBC驱动程序的元数据或查询参数。日志对开发整个阶段都是有益的。我经常检查应用程序在开发期间、测试期间和产品中的日志记录。
在这段中,我们将展现一段如何把Jakarta  Commaons  Logging结合中一个DAO中的例子。在我们开始之前,让我们先回顾一些基础知识。

选择一个日志例库
许多开发人员使用的基本日志形式是:System.out.println和System.err.println.Println语句。这种形式快捷方便,但它们不能提供一个完整的日志系统的的能力。下表列出了Java平台的日志类库:
日志类库        开源吗?        URL
Java.util.logging        否        http://java.sun.com/j2ee

Jakarta  Log4j        是        http://hajarta.apache.org/log4j/
Jakarta  Commons  Logging        是        http:/Jakarta.apache.org/commons/logging.html

Java.util.logging是J2SE1.4平台上的标准的API。但是,大多数开发人员都认为Jakarta  Log4j提供了更大的功能性和灵活性。Log4j超越java.util.logging的优点之一就是它支持J2SE1.3和J2SE1.4平台。

Jakarta  Commons  Logging能够被用于和java.util.loggin或Jakarta  Log4j一起工作。Commons  Logging是一个把你的应用程序独立于日志实现的提取层。使用Commons  Logging你能够通过改变一个配置文件来与下面的日志实现来交换数据。Commons  Logging被用于JAKARTA  Struts1.1和Jakarta  HttpClient2.0中。

一个日志示例
示例7显示了在一个DOA类中怎样使用Jakarta  Commons  Logging

程序代码:import org.apache.commons.logging.*;
class document.AOImpl implements document.AO
{
      static private final Log log = LogFactory.getLog(document.AOImpl.class);
      public void deletedocument.String id)
      {
          // ...
          log.debug("deleting document. " + id);
          // ...
          try
          {
              // ... data operations ...
          }
          catch (SomeException ex)
          {
              log.error("Unable to delete document.quot;, ex);
              // ... handle the exception ...
  }
      }
}



日志是评估应用程序的基本部分。如果你在一个DAO中遇到了失败,日志经常会为理解发生的什么错误提供最好的信息。把日志结合到你的DAO中,确保得到调试和解决问题的有效手段。

DAO中的异常处理
我们已经看了事务划分和日志记录,并且现在对于它们是怎样应用于数据访问对象的有一个深入的理解。我们第三部分也是最后要讨论的是异常处理。下面的一些简单的异常处理方针使用你的DAO更容易使用,更加健壮和更具有可维护性。

在实现DAO模式的时候,要考滤下面的问题:
.在DAO的public接口中的方法将抛出被检查的异常吗?
.如果是,将抛出什么样的检查性异常?
.在DAO实现类中怎能样处理异常。
在用DAO模式工作的过程中,我们的团队为异常处理开发了一组方针。下面的这些方针会很大程度的改善你的DAO:
.DAO方法应该抛出有意义的异常。
.DAO方法不应该抛出java.lang.Exception异常。因为java.lang.Exception太一般化,它不能包含有关潜在问题的所有信息。
.DAO方法不应该抛出java.sql.SQLException异常。SQLException是一个底层的JDBC异常,DAO应用努力封装JDBC异常而不应该把JDBC异常留给应用程序的其它部分。
.在DAO接口中的方法应该只抛出调用者期望处理的检查性异常。如果调用者不能用适当的方法来处理异常,考滤抛出不检查性(运行时run-time)异常。

.如果你的数据访问代码捕获了一个异常,不可要忽略它。忽略捕获异常的DAO是很处理的。
.使用异常链把底层的异常传递给高层的某个处理器。
.考滤定义一个标准的DAO异常类。Spring框架提供了一个优秀的预定义的DAO异常类的集合。
看Resources,查看有异常和异常处理技术的更详细信息。

实现示例:MovieDAO
MoveDAO是一个示范了在这篇文章中所讨论的所有技术,包括事务划分、日志记录和异常处理。你会在Resources段找到MovieDAO的源代码。它被分下面的三个包:

程序代码:.daoexamples.exception
.daoexamples.move
.daoexamples.moviedemo



这个DAO模式的实现由下面的类和接口组成:

程序代码:.daoexamples.movie.MovieDAOFactory
.daoexamples.movie.MovieDAO
.daoexamples.movie.MovieDAOImpl
.daoexamples.movie.MovieDAOImplJTA
.daoexamples.movie.Movie
.daoexamples.movie.MovieImple
.daoexamples.movie.MovieNotFoundException
.daoexamples.movie.MovieUtil



MovieDAO接口定义了DAO的数据操作。这个接口有如下五个方法:

程序代码:.public Movie findMovieById(String id)
.public java.util.Collection findMoviesByYear(String year)
.public void deleteMovie(String id)
.public Movie createMovie(String rating,String year,String title)
.public void updateMovie(String id,String rating,String year,String title)


daoexamples.movie包包含了两个MovieDAO接口的实现。每个实现使用了一个同的事务划分方法,如下表所示:
       MovieDAOImpl        MovieDAOImplJTA
实现了MovieDAO接口吗?        Yes        Yes
通过JNDI获得DataSource吗?        Yes        Yes
从一个DataSource获得java.sql.Connection对象吗?        Yes        Yes
DAO界定内部的事务吗?        Yes        No
使用JDBC事务吗?        Yes        No
使用一个XA  DataSource吗?        No        Yes
分担JTA事务吗?        No        Yes


MovieDAO  示范应用程序
这个示范应用程序是一个叫做daoexamples.moviedemo.DemoServlet.DemoServlet的servlet类,它使用Movie  DAO来查询和更新一个表中的movie数据。

这个servlet示范了把JTA感知的MovieDAO和Java消息服务组合到一个单一的事务中,如示例8所示:

程序代码:UserTransaction utx = MovieUtil.getUserTransaction();
utx.begin();
batman = dao.createMovie("R",
      "2008",
      "Batman Reloaded");
publisher = new MessagePublisher();
publisher.publishTextMessage("I'll be back");
dao.updateMovie(topgun.getId(),
      "PG-13",
      topgun.getReleaseYear(),
      topgun.getTitle());
dao.deleteMovie(legallyblonde.getId());
utx.commit();



要运行这个范例应用程序,在你的应用程序服务器中配置一个XA  数据源和一个非XA数据源。然后布署daoexamples.ear文件。这个应用程序将运行在任何与J2EE兼容的应用程序服务器。