在供應鏈管理系統開發中,我們大量使用 DAO 模式隔離資料存取邏輯。本文分享構建生產級 DAO 的三大核心技術:事務界定、日誌記錄、異常處理,附完整 MovieDAO 實戰範例(含 JDBC/JTA 兩種事務實作)。
設計 DAO 前必須回答七個關鍵問題:事務如何開始/結束?由誰負責?DAO 是否界定?是否跨多個 DAO/資料庫?DAO 之間是否互呼叫?
// JDBC 事務界定
DataSource ds = obtainDataSource();
Connection conn = ds.getConnection();
conn.setAutoCommit(false);
try {
// 多條 SQL 操作
conn.commit();
} catch (Exception e) {
conn.rollback();
throw e;
} finally { close(conn); }
優點:簡單、封裝性好。缺點:無法跨多個資料庫、無法跨多個 DAO 協調單一事務。
// JTA 事務界定
UserTransaction utx = lookupUserTransaction();
utx.begin();
try {
dao1.createX();
dao2.updateY();
jmsSender.sendMessage();
utx.commit();
} catch (Exception e) {
utx.rollback();
throw e;
}
DAO 類別不含事務碼,僅執行 SQL;需使用 XADataSource、XAConnection、XAResource 實作驅動;嚴禁在 XA 連線上呼叫 JDBC commit/rollback,必須委託 UserTransaction。
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); // 保留堆疊追蹤
throw ex;
}
}
}
優勢:抽象層隔離底層實作,配置檔切換 Log4j/java.util.logging;記錄異常、配置、連線狀態、驅動元資料、查詢參數,覆蓋開發/測試/生產全生命週期。
throw new MyDaoException("msg", rootCause))保留根因;建議採用 Spring 等框架預定義的 DAO 異常體系。MovieDAOFactory、MovieDAO 介面、MovieDAOImpl (JDBC 內部事務)、MovieDAOImplJTA (JTA 外部事務)Movie 介面與 MovieImpl (DTO/VO)MovieNotFoundException 等自訂異常掌握這三大支柱,DAO 從單純的資料存取類別昇華為可靠、可觀測、可維護的企業級資料存取層基石。