??xml version="1.0" encoding="utf-8" standalone="yes"?>久久久久久久电影,亚洲视频在线免费观看,一本大道香蕉久在线播放29http://www.aygfsteel.com/victor/category/572.html享受喧嚣 安于q静zh-cnTue, 27 Feb 2007 17:30:23 GMTTue, 27 Feb 2007 17:30:23 GMT60高 DAO ~程http://www.aygfsteel.com/Victor/articles/1674.htmlVictorVictorFri, 04 Mar 2005 01:21:00 GMThttp://www.aygfsteel.com/Victor/articles/1674.htmlhttp://www.aygfsteel.com/Victor/comments/1674.htmlhttp://www.aygfsteel.com/Victor/articles/1674.html#Feedback0http://www.aygfsteel.com/Victor/comments/commentRss/1674.htmlhttp://www.aygfsteel.com/Victor/services/trackbacks/1674.htmlJ2EE 开发h员用数据访问对?Data Access Object DAO)设计模式Q以便将低别的数据讉K逻辑与高U别的业务逻辑分离。实?DAO 模式涉及比编写数据访问代码更多的内容。在本文中,Java 开发h?Sean C. Sullivan 讨论?DAO ~程中三个常常被忽略的方面:事务界定、异常处理和日志记录?/BLOCKQUOTE>

在过?18 个月中,我参加了一个由有才华的软g工程师组成的组Q构建定制的、基?Web 的供应链理应用E序。我们的应用E序讉K范围q泛的持久性数据,包括配送状态、供应链衡量(metrics)、库存、货q发、项目管理数据和用户信息。我们用 JDBC API q接到我们公司的不同数据库^CQƈ在整个应用程序中使用 DAO 设计模式?/P>

?1 昄了应用程序和数据源之间的关系Q?/P>

?1. 应用E序和数据源
应用E序和数据源

在整个应用程序中使用数据讉K对象(DAO)使我们可以将底层数据讉K逻辑与业务逻辑分离开来。我们构Z为每一个数据源提供 GRUD (创徏、读取、更新、删?操作?DAO cR?/P>

在本文中Q我ؓ您介l构建更好的 DAO cȝ DAO 实现{略和技术。更切地说Q我讨论日志、异常处理和事务界定。您学到如何将q三者结合到自己?DAO cM。本文假定您熟悉 JDBC API、SQL 和关pL据库~程?/P>

我们以?DAO 设计模式和数据访问对象的概述开始?/P>

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

  • 一?DAO 工厂c?
  • 一?DAO 接口
  • 一个实C DAO 接口的具体类
  • 数据传输对象(有时UCؓ值对?

具体?DAO cd含访问特定数据源的数据的逻辑。在下面一节中您将学习设计和实现数据访问对象的技术。有?DAO 设计模式的更多内容请参阅 参考资?/A>?/P>

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

事务界定是定义事务边界的方式。J2EE 规范描述了两U事务界定的模型Q编E式(programmatic)和声明式(declarative)。表 1 分析了这两种模型Q?/P>

?1. 两种事务界定的模?/B>
声明式事务界?/B> ~程式事务界?/B>
E序员用 EJB 部v描述W声明事务属性?/TD> E序员负责编写事务逻辑?/TD>
q行时环?EJB 容器)用这些属性自动管理事务?/TD> 应用E序通过一?API 控制事务?/TD>

我们侧重于~程式事务界定?/P>

设计考虑
如前所qͼDAO 是事务性对象。一个典型的 DAO 执行像创建、更新和删除q样的事务性操作。在设计 DAO Ӟ首先要问自己以下问题Q?/P>

  • 事务要如何开始?
  • 事务应如何结束?
  • 哪一个对象将负责开始一个事务?
  • 哪一个对象将负责l束一个事务?
  • DAO 是否要负责事务的开始和l束Q?
  • 应用E序是否需要通过多个 DAO 讉K数据Q?
  • 事务涉及C?DAO q是多个 DAOQ?
  • 一?DAO 是否调用另一?DAO 的方法?

了解上述问题的答案将有助于您选择最适合?DAO 的事务界定策略。在 DAO 中有两种主要的界定事务的{略。一U方式是?DAO 负责界定事务Q另一U将事务界定交给调用q个 DAO Ҏ的对象处理。如果选择了前一U方式,那么将事务代码嵌入?DAO 中。如果选择后一U方式,那么事务界定代码是?DAO cd面。我们将使用单的代码CZ帮助您更好理解每一U方式是如何工作的?/P>

清单 1 昄了一个有两种数据操作?DAOQ创建和更新Q?/P>清单 1. DAO Ҏ

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

清单 2 昄了一个简单的事务。事务界定在 DAO cd面。注意在q个例子中调用者是如何在一个事务中l合多个 DAO 操作的?/P>清单 2. 调用者管理的事务

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

q种事务界定{略对于需要在一个事务中讉K多个 DAO 的应用程序特别有用?/P>

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

?JDBC q行事务界定
JDBC 事务是用 Connection 对象控制的。JDBC Connection 接口(java.sql.Connection)提供了两U事务模式:自动提交和手工提交?CODE>java.sql.Connection 提供了以下控制事务的ҎQ?/P>

  • public void setAutoCommit(boolean)
  • public boolean getAutoCommit()
  • public void commit()
  • public void rollback()

清单 3 昄了如何用 JDBC API 界定一个事务:

清单 3. ?JDBC API q行事务界定

      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 语句l合C个事务中。JDBC 事务的一个缺Ҏ事务的范围局限于一个数据库q接。一?JDBC 事务不能跨越多个数据库。在下面Q我们将看一下如何用 JTA q行事务界定。因?JTA 不像 JDBC 那样有名Q所以我们首先做一个简介?/P>

JTA ?/SPAN>
Java 事务 API(JTA) 及其同门兄弟 Java 事务服务(Java Transaction Service JTS)?J2EE q_提供了分布式事务服务。一?I xmlns:dw="http://www.ibm.com/developerWorks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">分布式的事务涉及一个事务管理器和一个或者多个资源管理器。一?I xmlns:dw="http://www.ibm.com/developerWorks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">资源理?/I>是Q何类型的持久性的数据存储。事务管理器负责协调所有事务参与者之间的通信。事务管理器与资源管理器之间的关pd?2 所C:

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

JTA 事务?JDBC 事务功能更强。JDBC 事务局限ؓ一个数据库q接Q?JTA 事务可以有多个参与者。所有下?Java q_lg都可以参?JTA 事务Q?/P>

  • JDBC q接
  • JDO PersistenceManager 对象
  • JMS 队列
  • JMS 主题
  • 企业 JavaBeans
  • W合 J2EE q接体系l构(J2EE Connector Architecture)规范的资源适配?

使用 JTA 的事务界?/SPAN>
要用 JTA q行事务界定Q应用程序要调用 javax.transaction.UserTransaction 接口中的Ҏ。清?4 昄了对 UserTransaction 对象的典?JNDI 查询Q?/P>清单 4. 一个对 UserTransaction 对象?/B> JDNI 查询


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

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

清单 5. ?JTA 开始一个事?/B>


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

当应用程序调?CODE> commit()Ӟ事务理器用一个两阶段的提交协议结束事务?/P>

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

  • public void begin()
  • public void commit()
  • public void rollback()
  • public int getStatus()
  • public void setRollbackOnly()
  • public void setTransactionTimeout(int)

应用E序调用 begin() 开始事务。应用程序调?commit() 或?CODE> rollback() l束事务。参?A xmlns:dw="http://www.ibm.com/developerWorks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">参考资?/A>以了解更多关于用 JTA q行事务理的内宏V?/P>

使用 JTA ?JDBC
开发h员通常?DAO cM?JDBC q行底层数据操作。如果计划用 JTA 界定事务Q那么就需要有一个实?javax.sql.XADataSource?CODE>javax.sql.XAConnection ?javax.sql.XAResource 接口?JDBC 驱动E序。一个实Cq些接口的驱动程序将可以参与 JTA 事务。一?CODE> XADataSource 对象是一?XAConnection 对象的工厂?CODE>XAConnections 是参?JTA 事务?JDBC q接?/P>

您将需要用应用服务器的理工具讄 XADataSource。从应用服务器和 JDBC 驱动E序的文档中可以了解到相关的指导?/P>

J2EE 应用E序?JNDI 查询数据源。一旦应用程序找C数据源对象,它就调用 javax.sql.DataSource.getConnection() 以获得到数据库的q接?/P>

XA q接与非 XA q接不同。一定要C XA q接参与?JTA 事务。这意味着 XA q接不支?JDBC 的自动提交功能。同Ӟ应用E序一定不要对 XA q接调用 java.sql.Connection.commit() 或?CODE> java.sql.Connection.rollback()。相反,应用E序应该使用 UserTransaction.begin()?/CODE>UserTransaction.commit() ?CODE> serTransaction.rollback()?/P>

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

在最q的许多目中,我们组是用 JDBC API q事务界定来构徏 DAO cȝ。这?DAO cd以ȝ如下Q?/P>

  • 事务界定代码嵌入?DAO cM?
  • DAO cM?JDBC API q行事务界定?
  • 调用者不能界定事务?
  • 事务范围局限于单个 JDBC q接?

JDBC 事务q不L适合复杂的企业应用程序。如果您的事务要跨越多个 DAO 或者多个数据库Q那么下列实现策略也许更合适:

  • 事务?JTA 界定?
  • 事务界定代码?DAO 中分d来?
  • 调用者负责界定事务?
  • DAO 加入一个全局事务?

JDBC 方式׃其简单性而具有吸引力QJTA 方式提供了更大的灉|性。您所选择的实现将取决于应用程序的特定需求?/P>

日志记录?DAO
一个良好实现的 DAO cd使用日志记录来捕捉有兛_q行时行为的l节。您可以选择记录异常、配|信息、连接状态、JDBC 驱动E序元数据、或者查询参数。日志对于开发的所有阶D都很有用。我l常在开发时、测试时和生产中分析应用E序日志?/P>

在本节,我将展示一个显C如何将 Jakarta Commons Logging 加入?DAO 中的代码CZ。在q之前,让我们回一下一些基本知识?/P>

选择日志?/SPAN>
许多开发h员用一U原始格式进行日志记录:System.out.println ?CODE> System.err.println?CODE>Println 语句速度快且使用方便Q但是它们没有提供全功能的日志记录系l所h的功能。表 2 列出?Java q_的日志库Q?/P>

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

java.util.logging ?J2SE 1.4 q_上的标准 API。不q,大多数开发h员同?Jakarta Log4j 提供了更多的功能和更大的灉|性。Log4j 优于 java.util.logging 的一Ҏ它同时支?J2SE 1.3 ?J2SE 1.4 q_?/P>

Jakarta Commons Logging 可以?CODE> java.util.logging 或?Jakarta Log4j 一同用。Commons Logging 是一个日志抽象层Q它隔离了应用程序与底层日志实现。?Commons LoggingQ您可以通过改变配置文g更换底层日志实现。Commons Logging ?Jakarta Struts 1.1 ?Jakarta HttpClient 2.0 中用?/P>

一个日志记录示?/SPAN>
清单 7 昄了如何在 DAO cM使用 Jakarta Commons LoggingQ?/P>清单 7. DAO cM?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 ...
	}
      }
}

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

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

在实?DAO 模式Ӟ考虑以下问题Q?/P>

  • DAO 的公共接口中的方法是否抛出检查过的异常?
  • 如果是的话,抛出何种查过的异常?
  • ?DAO 实现cM如何处理异常Q?

在?DAO 模式的过E中Q我们的组开发了一些处理异常的原则。遵从这些原则可以极大地改进您的 DAOQ?/P>

  • DAO Ҏ应该抛出有意义的异常?BR>
  • DAO Ҏ不应该抛?java.lang.Exception?CODE>java.lang.Exception 太一般化了。它不传递关于底层问题的M信息?BR>
  • DAO Ҏ不应该抛?CODE> java.sql.SQLException。SQLException 是一个低U别?JDBC 异常。一?DAO 应该力争装 JDBC 而不是将 JDBC 公开l应用程序的其余部分?BR>
  • 只有在可以合理地预期调用者可以处理异常时QDAO 接口中的Ҏ才应该抛出检查过的异常。如果调用者不能以有意义的方式处理q个异常Q那么考虑抛出一个未查的(q行?异常?BR>
  • 如果数据讉K代码捕获了一个异常,不要忽略它。忽略捕L异常?DAO 是很难进行故障诊断的?BR>
  • 使用链接的异常将低别的异常转化为高U别的异常?BR>
  • 考虑定义标准 DAO 异常cRSpring Framework (参阅参考资?/A>)提供了很好的一套预定义?DAO 异常cR?

有关异常和异常处理技术的更多信息参阅参考资?/A>?/P>

实现实例Q?MovieDAO
MovieDAO 是一个展C本文中讨论的所有技术的 DAOQ事务界定、日志和异常处理。您可以?A xmlns:dw="http://www.ibm.com/developerWorks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">参考资?/A>一节中扑ֈ MovieDAO 源代码。代码分Z个包Q?/P>

  • daoexamples.exception
  • daoexamples.movie
  • daoexamples.moviedemo

DAO 模式的这个实现包含下面列出的cd接口Q?/P>

  • 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 的数据操作。这个接口有五个ҎQ如下所C:

  • 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 接口的两个实现。每一个实C用一U不同的方式q行事务界定Q如?3 所C:

?3. MovieDAO 实现
MovieDAOImpl MovieDAOImplJTA
实现 MovieDAO 接口? ?/TD> ?/TD>
通过 JNDI 获得 DataSourceQ?/TD> ?/TD> ?/TD>
?DataSource 获得 java.sql.Connection 对象Q?/TD> ?/TD> ?/TD>
DAO 在内部界定事务? ?/TD> ?/TD>
使用 JDBC 事务Q?/TD> ?/TD> ?/TD>
使用一?XA DataSourceQ?/TD> ?/TD> ?/TD>
参与 JTA 事务Q?/TD> ?/TD> ?/TD>

MovieDAO 演示应用E序
q个演示应用E序是一个名?daoexamples.moviedemo.DemoServlet ?servlet cR?CODE>DemoServlet 使用q两?Movie DAO 查询和更新表中的电媄数据?/P>

q个 servlet 展示了如何将支持 JTA ?MovieDAO ?Java 消息服务(Java Message Service)l合C个事务中Q如清单 8 所C?/P>清单 8. ?MovieDAO ?JMS 代码l合C个事务中

	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();

要运行这个演C应用程序,需要在应用服务器上配置一?XA 数据源和一个非 XA 数据源。然后,部v daoexamples.ear 文g。这个应用程序可以在M兼容 J2EE 1.3 的应用服务器上运行。参?A xmlns:dw="http://www.ibm.com/developerWorks/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">参考资?/A>以获?EAR 文g和源代码?/P>

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

Victor 2005-03-04 09:21 发表评论
]]>
վ֩ģ壺 | | Ϫ| Դ| | Զ| | | | ͭ| | ն| | üɽ| | | ʦ| ƽ| ˮ| | | | | | | Ϫ| | | | ͨ| ʯ| | ݸ| ؼ| | | | | ޶| ʶ| |