在核心J2EE模式中是这样介绍DAO模式的:为了建立一个健壮的J2EE应用,应该将所有对数据源的访问操作抽象封装在一个公共API中。用程序设计的语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口在逻辑上对应这个特定的数据存储。
比如考虑在iBatis: SQL Maps中的应用例子。这是一个Struts应用答应对一个关系表执行SELECT, INSERT, UPDATE和DELETE的SQL请求。在这个应用中,使用SQL Maps做持续性框架。现在我们要修改这个应用,将这个关系表储存在一个xml文件中而不是存在关系数据库中,或者使用Hibernate来实现SELECT请求,而用SQL Map来执行其他请求,因为Hibernate提供了对高速缓存更好的支持。这样的修改很难实现,或者即使我们能修改而实现了这个功能,也会是很混乱的解决方案。
对于这类问题更好的解决方法是建立一个ContactDAO接口,在这个接口中定义处理SELECT, INSERT, UPDATE, 和DELETE 请求的事务方法。然后根据不同的事务逻辑建立不同的类实现各个方法。所以可能会有一个类处理使用SQL Maps同关系表进行交互的情况,而另外一个类处理用XML文件存放关系表而不是关系数据库的情况,等等。在项目中,根据实际的需要从不同的ContactDAO中选择相应的实现。这种关系见图1:
图1. ContactDAO 接口及实现
iBatis DAO是由Apache主持的开源框架项目,主要目标是为了解决这类问题。它答应在工程中以DAO模式为基础建立应用。这就意味着可以建立一个XML文件,并声明XMLContactDAO.java是ContactDAO的实现类,这个类知道如何从XML文件中读写数据。SQLMapContactDAO则知道如何用SQL Maps作为持续化框架与关系表进行交互。在工程中,假如向DAO框架提交一个需要XML的ContactDAO请求,框架则会返回一个XMLContactDAO对象。同样的DAO框架提供了唯一的接口处理事务治理,这个接口能实现与数据的存储方式无关。它同样考虑了底层连接治理细节和初始化存储框架。
这篇文章是关于如何一步一步的在项目中应用iBatis DAO框架的基础指导。我们将由如何把SQL Maps一文中的应用实例改为应用DAO框架入手。然后,我们要讨论DAO框架的构造。再下一步,我们关注事务治理是如何在DAO框架中得到支持的。最后一部分是关于如何建立自己的事务治理模块。
示例应用
首先,我们将SQL Maps一文中的例子改为应用DAO框架。
1. 将ibatis-dao-2.jar文件复制到WEB-INF/lib目录下。
2. 在Java源程序的目录里新建一个如下的DAOMap.xml文件
清单1:
PRoperty value="
"com/sample/contact/dao/sqlmap/SqlMapConfig.xml"/>
implementation=
"com.sample.contact.dao.sqlmap.SQLMapContactDAO"/>
DAOMap.xml是发布iBatis DAO框架的配置文件。是根元素,每个元素描述了一种存储机制。在这个例子中只使用了SQL Maps来存储,所以我们这里只有一个元素。每种存储机制必须包含一个元素,这个元素描述连接它后面的数据存储所用的治理器,并且标记事务的界限。我们将在稍后再讨论transactionManager。
元素还包括一组DAO用于描述其他的存储治理机制。在这个例子中,我们将生成一个使用SQL Maps存储的ContactDAO,所以在配置文件中添加一个ie标记来定义SQLMapContactDAO。
3. 建立ContactDAO.java,如下:
单2:
public interface ContactDAO extends DAO {
public int insertContact(Contact contact);
public int updateContact(Contact contact);
public Contact selectContact(int contactId);
public int deleteContact(int contactId);
}
ContactDAO.java定义了用户和一个关系表进行交互所需要用到的所有事务处理方法。请注重到ContactDAO.java中的所有方法都将一个Contact对象作为参数,这是一个用来携带数据的数据传递对象。
4. 建立一个SQLMapContactDAO.java文件,如下
清单3:
public class SQLMapContactDAO extends
SqlMapDaoTemplate implements ContactDAO {
public SQLMapContactDAO(DaoManager arg0) {
super(arg0);
}
public int deleteContact(int contactId) {
return super.delete("deleteContact",
new Integer(contactId));
}
public int insertContact(Contact contact) {
Integer contactId =(Integer)super.insert
("insertContact",contact);
return contact.getContactId();
}
public Contact selectContact(int contactId) {
return (Contact)super.queryForObject("getContact",
new Integer(contactId));
}
public int updateContact(Contact contact) {
return super.update("updateContact",contact);
}
}
SQLMapContactDAO是ContactDAO接口的具体实现,它用SQL Maps作为存储治理机制。注重到我们并没有写任何代码来或者初始化SQL Maps,或得到一个连接,或者在类中标注一个事务的界限。相反,我们继续SqlMapDaoTemplate.java类,它帮我们处理下层的、反复的操作。我们在SQLMapContactDAO类中需要考虑的唯一的事情就是事务处理逻辑。
5. 修改ContactSelectAction.java类中的execute()方法,如下:
清单4:
Contact contactForm = (Contact) form;
Reader reader=
Resources.getResourceAsReader("DAOMap.xml");
DaoManager daoManager =
DaoManagerBuilder.buildDaoManager(reader);
ContactDAO contactDAO =
(ContactDAO) daoManager.getDao(
ContactDAO.class,"sqlmap");
request.setAttribute("contactDetail",
contactDAO.selectContact(
contactForm.getContactId()));
最后一步是修改ContactSelectAction类中的execute()方法,使它使用DAO框架。为了初始化DAO框架,我们需要一个为DAOMap.xml 预备一个Reader对象。iBatis框架为我们提供了方法Resources.getResourceAsReader()来读取资源。一旦有了Reader对象来读取DAOMap.xml,就能将它们读取至DAOManagerBuilder.buildDaoManager(),返回一个DaoManager实例,将来用于与DAO框架进行交互。从理论上来说,应该在项目启动的时候初始化DAO框架,在我们这个程序中,可以将这个模块放入Struts插件中,但是为了简化这个例子,我们将初始化模块放入execute方法中。
有了DaoManager实例后,可以调用相应的接口和存储实现类(在元素中的id属性值)的getDao()方法。在我们的例子中,需要一个SQLMapContactDAO的实例,所以以ContactDAO为接口名称,“sqlmap”为存储机制。一旦实现了SQLMapContactDAO实例,就可以在调用其中的事务方法。