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

JPA 設計模式實戰 (一):型別安全的泛型 DAO 模式與 EntityManager 整合

     編輯:Java 相關知識

JPA (Hibernate、EclipseLink、OpenJPA 等) 雖簡化持久化,但實務專案仍需解決:事務邊界、延遲載入、實體移除、繼承映射等問題。本系列首篇建立**型別安全、可測試、框架無關**的泛型 DAO 基礎架構。

為什麼需要 DAO?

  • 隔離 EntityManager 依賴,業務碼不直接呼叫 JPA API
  • 集中管理查詢,避免 HQL/JPQL 散落各處
  • 可對特定實體限制操作 (如 LogEntry 僅允許新增查詢,禁止刪除)
  • 理論上可切換持久化實作 (JDBC/iBATIS),實務上 JPA 本身即抽象層
  • 便於單元測試:Mock DAO 介面即可

領域實體範例

@Entity @Table(name="ORDERS")
public class Order {
    @Id @GeneratedValue
    private int id;
    private String customerName;
    private Date date;
    // getters/setters
}

泛型 DAO 介面

public interface Dao<K, E> {
    void persist(E entity);
    void remove(E entity);
    E findById(K id);
    List<E> findAll(); // 可選擴充
}

K = 主鍵型別,E = 實體型別。

具體實體 DAO 介面

public interface OrderDao extends Dao<Integer, Order> {
    List<Order> findOrdersSubmittedSince(Date date);
}

JPA 基礎實現 (抽象父類)

public abstract class JpaDao<K, E> implements Dao<K, E> {
    protected Class<E> entityClass;

    @PersistenceContext
    protected EntityManager entityManager;

    @SuppressWarnings("unchecked")
    public JpaDao() {
        ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
        this.entityClass = (Class<E>) genericSuperclass.getActualTypeArguments()[1];
    }

    public void persist(E entity) { entityManager.persist(entity); }
    public void remove(E entity) { entityManager.remove(entity); }
    public E findById(K id) { return entityManager.find(entityClass, id); }
    public List<E> findAll() { 
        return entityManager.createQuery("SELECT e FROM " + entityClass.getName() + " e").getResultList();
    }
}

關鍵技術點

  1. 構造器解析泛型:透過 getGenericSuperclass() 取得實際型別參數 E,避免子類重複指定
  2. @PersistenceContext 注入:容器管理 EntityManager,支援 EJB3 / Spring (需 PersistenceAnnotationBeanPostProcessor)
  3. protected 成員:子類可直接存取 entityManager、entityClass 撰寫複雜查詢

具體 DAO 實現


public class JpaOrderDao extends JpaDao<Integer, Order> implements OrderDao {
    public List<Order> findOrdersSubmittedSince(Date date) {
        Query q = entityManager.createQuery(
            "SELECT e FROM " + entityClass.getName() + " e WHERE e.date >= :date_since");
        q.setParameter("date_since", date);
        return q.getResultList();
    }
}

依賴注入使用

EJB 3 環境

@EJB(name="orderDao")
private OrderDao orderDao;

Spring 環境

@Autowired
private OrderDao orderDao;

業務代碼範例

// 新增
Order o = new Order();
o.setCustomerName("Peter Johnson");
o.setDate(new Date());
orderDao.persist(o);

// 查詢
List<Order> orders = orderDao.findOrdersSubmittedSince(cutoffDate);
for (Order each : orders) {
    System.out.println("order id = " + each.getId());
}

型別安全 DAO 模式優勢總結

  1. 客戶端零 JPA API 依賴
  2. 泛型消除強制轉型風險
  3. 查詢邏輯集中、可測試
  4. 切面點統一加入事務、日誌、效能監控
  5. 單一類別完整測試資料存取層

下一篇預告

雙向關聯映射模式:@OneToMany/@ManyToOne 同步維護、mappedBy 陷阱、延遲載入最佳實踐。

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