Java数据访问对象(DAO)编程模入门
使用JTA的事务划分
要用JTA来划分一个事务,应用程序调用javax.transaction.UserTransaction接口中的方法。示例4显示了一个典型的JNDI搜索的UseTransaction对象。
import javax.transaction.*;
import javax.naming.*;
// ...
InitialContext ctx = new InitialContext();
Object txObj = ctx.lookup(";java:comp/UserTransaction";);
UserTransaction utx = (UserTransaction) txObj;
应用程序有了UserTransaction对象的引用之后,就可以象示例5那样来起动事务。
.javax.transaction.UserTransaction接口提供了下列事务控制方法:
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事务控制的方法:
.public void begin()
.public void commit()
.public void rollback()
.public void getStatus()
.public void setRollbackOnly()
.public void setTransactionTimeout(int)
应用程序调用begin()来起动事务,即可调用commit()也可以调用rollback()来结束事务。
使用JTA和JDBC
开发人员经常使用JDBC来作为DAO类中的底层数据操作。如果计划使用JTA来划分事务,你将需要一个实现了Javax.sql.XADataSource,javax.sql.XAConnection和javax.sql.XAResource接口JDBC的驱动。实现了这些接口的驱动将有能力参与到JTA事务中。一个XADataSource对象是一个XAConnection对象的工厂。XAConnections是参与到JTA事务中的连接。
你需要使用应用程序服务器管理工具来建立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()和UserTransaction.rollback().
选择最好的方法
我们已经讨论了JDBC和JTA是怎样划分事务的。每一种方法都有它的优点,回此你需要决定为你的应用程序选择一个最适应的方法。在我们团队许多最近的对于事务划分的项目中使用JDBC API来创建DAO类。这DAO类总结如下:
·事务划分代码被嵌入到DAO类内部
·DAO类使用JDBC API来进行事务划分
·调用者没有划分事务的方法
·事务范围被限定在一个单一的JDBC连接
JDBC事务对复杂的企业应用程序不总是有效的。如果你的事务将跨越多个DAO对象或多个数据库,那么下面的实现策略可能会更恰当:
·用JTA对事务进行划分
·事务划分代码被DAO分开
·调用者承担划分事务的责任
·DAO参与一个全局的事务中
JDBC方法由于它的简易性而具有吸引力,JTA方法提供了更多灵活性。你选择什么样的实现将依赖于你的应用程序的特定需求。
日志记录和DAO
一个好的DAO实现类将使用日志记录来捕获有关它在运行时的行为细节。你可以选择记录异常、配置信息、连接状态、JDBC驱动程序的元数据或查询参数。日志对开发整个阶段都是有益的。我经常检查应用程序在开发期间、测试期间和产品中的日志记录。
在这段中,我们将展现一段如何把Jakarta Commaons Logging结合中一个DAO中的例子。在我们开始之前,让我们先回顾一些基础知识。
一个日志示例
示例7显示了在一个DOA类中怎样使用Jakarta Commons Logging
这个servlet示范了把JTA感知的MovieDAO和Java消息服务组合到一个单一的事务中,如示例8所示:
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的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数据。
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兼容的应用程序服务器。
0
相关文章