在開發 J2EE 企業級應用時,資料持久化是核心課題。無論是產品目錄、用戶資料還是圖書管理系統,我們都需要將業務資訊映射到關聯式資料庫中。傳統做法是直接在業務邏輯中穿插 SQL 語句,這不僅導致程式碼耦合度高,也讓後續維護成為噩夢。本文將介紹一種經典且實用的「實體類別 + 會話類別」設計模式,並探討其在 J2EE 環境下的實作細節與交易處理考量。
實體類別對應資料表中的單筆記錄。每個實體類別的實例代表資料表中的一列,其屬性與資料欄位一一對應。以圖書查詢系統為例,Book 類別封裝了書號、書名、作者、出版社 ID、價格、頁數等欄位,並僅提供 getter/setter 方法,不包含任何業務邏輯或資料庫操作。
public class Book {
private int id;
private String name;
private String isbn;
private String author;
private int publisherId;
private double price;
private int volume;
// 標準 getter/setter 及建構子省略
}
同理,Publisher 類別對應出版社資料表。實體類別的實例僅存在於記憶體中,對其修改不會立即同步至資料庫,這提供了批次處理與交易控制的彈性。
會話類別負責對整張資料表進行 CRUD(建立、讀取、更新、刪除)操作。它扮演資料存取層(DAO)的角色,將 JDBC 細節封裝起來,對外提供語意清晰的方法:
public class BookTable {
public void add(Book book); // 新增記錄
public void delete(Book book); // 刪除記錄
public void update(Book book); // 更新記錄
public Collection findById(int id); // 主鍵查詢
public Collection findByPublisherName(String name); // 業務查詢
}
當涉及多表關聯查詢(如「查詢某出版社的所有書籍」)時,可在 BookTable 中新增 findByPublisherName 方法回傳 Book 集合,避免在業務層手工拼裝 SQL。
雖然此模式可直接對應 Entity Bean(實體)與 Session Bean(會話),但 EJB 並非銀彈:
本文聚焦於非 EJB 環境下的實作,採用 JDBC 直連資料庫,搭配連線池(如 DBCP、C3P0)提升效能。
JDBC Connection 預設為 auto-commit=true,每條 SQL 獨立成交易。若需將多條 SQL 納入同一交易,必須關閉自動提交:
Connection con = dataSource.getConnection();
try {
con.setAutoCommit(false); // 開啟交易
PreparedStatement ps1 = con.prepareStatement("UPDATE books SET stock = stock - 1 WHERE id = ?");
ps1.setInt(1, bookId);
ps1.executeUpdate();
PreparedStatement ps2 = con.prepareStatement("INSERT INTO orders (book_id, user_id) VALUES (?, ?)");
ps2.setInt(1, bookId);
ps2.setInt(2, userId);
ps2.executeUpdate();
con.commit(); // 全部成功才提交
} catch (SQLException e) {
con.rollback(); // 任一失敗全盤回滾
throw e;
} finally {
con.setAutoCommit(true); // 恢復預設行為
con.close();
}
關鍵點:commit() 前的所有 SQL 視為同一交易單位;rollback() 可確保資料不處於中間狀態。
當交易跨越多個資料庫或資源管理器(如同時更新資料庫與發送 JMS 訊息)時,需引入 Java Transaction API (JTA) 與 Java Transaction Service (JTS)。應用程式透過 UserTransaction 介面控制交易邊界,容器負責協調雙階段提交(Two-Phase Commit)。若使用 EJB,更可透過部署描述檔(ejb-jar.xml)以宣告式方式定義交易屬性(Required、RequiresNew 等),完全免除手工交易管理代碼。
maxActive、maxIdle 等參數應對尖峰流量。SQLException 包裝為非檢查型業務異常(如 DataAccessException),避免 JDBC 細節洩漏至表現層。「實體類別 + 會話類別」模式雖然簡單,卻是建構健壯資料存取層的基石。它不綁定特定框架,既能服務於輕量級 Servlet 應用,也能平滑遷移至 EJB 或 Spring/Hibernate 架構。掌握其精髓,配合嚴謹的交易控制,即可打造出既高效又可維護的 J2EE 資料存取核心。