首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2EE

深度解析 J2EE 應用程式資料庫類別設計模式:實體與會話類別的協作藝術

     編輯:J2EE

前言:為何需要資料庫類別設計模式?

在開發 J2EE 企業級應用時,資料持久化是核心課題。無論是產品目錄、用戶資料還是圖書管理系統,我們都需要將業務資訊映射到關聯式資料庫中。傳統做法是直接在業務邏輯中穿插 SQL 語句,這不僅導致程式碼耦合度高,也讓後續維護成為噩夢。本文將介紹一種經典且實用的「實體類別 + 會話類別」設計模式,並探討其在 J2EE 環境下的實作細節與交易處理考量。

一、 設計模式核心概念:實體與會話的分工

1.1 實體類別 —— 資料的記憶體映射

實體類別對應資料表中的單筆記錄。每個實體類別的實例代表資料表中的一列,其屬性與資料欄位一一對應。以圖書查詢系統為例,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 類別對應出版社資料表。實體類別的實例僅存在於記憶體中,對其修改不會立即同步至資料庫,這提供了批次處理與交易控制的彈性。

1.2 會話類別 —— 資料操作的統一入口

會話類別負責對整張資料表進行 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。

1.3 模式優勢總結

  • 高內聚低耦合:資料結構與操作邏輯分離,便於單元測試與維護。
  • 可遷移性:若未來切換至 EJB 或 ORM 框架,僅需替換會話類別實作。
  • 交易邊界清晰:會話類別方法天然成為交易的基本單位。

二、 J2EE 環境下的實作策略:EJB vs. 純 Java

雖然此模式可直接對應 Entity Bean(實體)與 Session Bean(會話),但 EJB 並非銀彈:

  • 分散式系統:EJB 容器提供交易、安全、叢集等企業級服務,大幅降低開發複雜度。
  • 單機/簡單應用:EJB 的遠端呼叫開銷(序列化、網路傳輸、容器攔截)會嚴重拖垮效能。此時採用「Servlet + 純 Java 類別 + JDBC」的輕量級架構更佳。

本文聚焦於非 EJB 環境下的實作,採用 JDBC 直連資料庫,搭配連線池(如 DBCP、C3P0)提升效能。

三、 交易處理:資料一致性的守護者

3.1 JDBC 本地交易控制

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() 可確保資料不處於中間狀態。

3.2 J2EE 分散式交易(JTA/JTS)

當交易跨越多個資料庫或資源管理器(如同時更新資料庫與發送 JMS 訊息)時,需引入 Java Transaction API (JTA) 與 Java Transaction Service (JTS)。應用程式透過 UserTransaction 介面控制交易邊界,容器負責協調雙階段提交(Two-Phase Commit)。若使用 EJB,更可透過部署描述檔(ejb-jar.xml)以宣告式方式定義交易屬性(Required、RequiresNew 等),完全免除手工交易管理代碼。

四、 最佳實踐建議

  1. 採用連線池:避免頻繁建立/關閉連線的開銷,配置 maxActive、maxIdle 等參數應對尖峰流量。
  2. 使用 PreparedStatement:防止 SQL 注入,並利用資料庫查詢計畫快取提升效能。
  3. 交易粒度適中:交易過大降低並發度,過小則無法保證業務一致性;以「業務用例」為邊界通常較合理。
  4. 異常轉換:將 SQLException 包裝為非檢查型業務異常(如 DataAccessException),避免 JDBC 細節洩漏至表現層。

結語

「實體類別 + 會話類別」模式雖然簡單,卻是建構健壯資料存取層的基石。它不綁定特定框架,既能服務於輕量級 Servlet 應用,也能平滑遷移至 EJB 或 Spring/Hibernate 架構。掌握其精髓,配合嚴謹的交易控制,即可打造出既高效又可維護的 J2EE 資料存取核心。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved