核心 J2EE 模式建議:將所有資料存取操作抽象為統一 API(介面),介面定義業務所需的所有事務方法。具體實作類別針對特定資料來源(關聯式 DB、XML、LDAP 等)實作介面。應用程式僅依賴介面,實作細節在部署時綁定,實現「資料存取邏輯與持久化機制解耦」。
假設原應用使用 iBatis SQL Maps 操作關聯表。現需求:
若無 DAO 層,業務代碼將充滿 if-else 判斷持久化策略,極難維護。引入 ContactDAO 介面,提供 XMLContactDAO、SQLMapContactDAO、HibernateContactDAO 多種實作,運行期由 DAO 框架依配置注入適當實例。
com.ibatis.dao.client.DAO 標記介面。SqlMapDaoTemplate(SQL Maps 專用)或 GenericDaoTemplate。dao.xml 宣告 <context>(交易管理器)、<dao>(介面→實作映射)。將 ibatis-dao-2.jar 放入 WEB-INF/lib。
<?xml version="1.0" encoding="UTF-8"?>
<daoConfig>
<context>
<transactionManager type="JDBC">
<property name="DataSource" value="java:comp/env/jdbc/mydb"/>
</transactionManager>
<property name="sqlMapConfig" value="com/sample/contact/dao/sqlmap/SqlMapConfig.xml"/>
</context>
<dao interface="com.sample.contact.dao.ContactDAO"
implementation="com.sample.contact.dao.sqlmap.SQLMapContactDAO"/>
</daoConfig>
public interface ContactDAO extends DAO {
int insertContact(Contact contact);
int updateContact(Contact contact);
Contact selectContact(int contactId);
int deleteContact(int contactId);
}
所有方法以 Contact DTO 傳遞資料,介面零 SQL Maps 依賴。
public class SQLMapContactDAO extends SqlMapDaoTemplate implements ContactDAO {
public SQLMapContactDAO(DaoManager manager) { super(manager); }
public int deleteContact(int contactId) {
return super.delete("deleteContact", new Integer(contactId));
}
public int insertContact(Contact contact) {
Integer id = (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);
}
}
關鍵點:繼承 SqlMapDaoTemplate 自動獲得 insert/delete/update/queryForObject 等模板方法,無需手動取得 SqlMapClient、管理連線、開關交易。專注於「呼叫哪個 SQL Map 陳述式」與「參數/結果轉換」。
public class ContactSelectAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
Contact contactForm = (Contact) form;
Reader reader = Resources.getResourceAsReader("dao.xml");
DaoManager daoManager = DaoManagerBuilder.buildDaoManager(reader);
ContactDAO contactDAO = (ContactDAO) daoManager.getDao(ContactDAO.class, "sqlmap");
request.setAttribute("contactDetail", contactDAO.selectContact(contactForm.getContactId()));
return mapping.findForward("success");
}
}
生產環境優化:DaoManager 應在應用啟動時(Struts PlugIn / ServletContextListener)建立單例,而非每請求建立。
下一篇將深入探討:
startTransaction()、commitTransaction()、rollbackTransaction())GenericDaoTemplate 支援 Hibernate、JDBC 等非 SQL Maps 持久層掌握 DAO 框架,讓持久化策略成為可插拔的組態選項,而非硬編碼的技術債。