1. 概述
本文將演示如何使用 Spring 和 JPA 實現 DAO。有關核心 JPA 配置,請參閲關於 Spring 中 JPA 的文章。
2. 停止使用 Spring 模板
從 Spring 3.1 版本開始,JpaTemplate 和相應的 JpaDaoSupport 已被標記為過時,建議使用原生 Java 持久性 API。
此外,這兩個類僅適用於 JPA 1.0 (根據 JpaTemplate 的 Javadoc 所示):
因此,現在最好直接使用 Java 持久性 API,而不是 JpaTemplate。請注意,該類未升級到 JPA 2.0,也不會升級。
2.1. 不使用模板的異常翻譯
JpaTemplate 的一項職責是 異常翻譯 – 將低級別的異常轉換為更高層次的通用 Spring 異常。
不使用模板時,對於所有帶有 @Repository 註解的 DAO,異常翻譯仍然啓用且完全功能。
Spring 使用一個 Bean 代理器來實現這一點,該代理器會為所有包含在容器中的 PersistenceExceptionTranslator 代理器周圍創建 @Repository 豆的代理。
此外,還應注意,異常翻譯機制使用代理 – 為了使 Spring 能夠圍繞 DAO 類創建代理,這些類不能聲明為 final。
3. DAO
首先,我們將實現所有 DAO 的基礎層——一個使用泛型和設計的抽象類,供後續擴展:
public abstract class AbstractJpaDAO< T extends Serializable > {
private Class< T > clazz;
@PersistenceContext
EntityManager entityManager;
public final void setClazz( Class< T > clazzToSet ){
this.clazz = clazzToSet;
}
public T findOne( long id ){
return entityManager.find( clazz, id );
}
public List< T > findAll(){
return entityManager.createQuery( "from " + clazz.getName() )
.getResultList();
}
public void create( T entity ){
entityManager.persist( entity );
}
public T update( T entity ){
return entityManager.merge( entity );
}
public void delete( T entity ){
entityManager.remove( entity );
}
public void deleteById( long entityId ){
T entity = findOne( entityId );
delete( entity );
}
}這裏最有趣的地方在於 EntityManager 的注入方式——使用標準的 @PersistenceContext 註解。在底層,這由 PersistenceAnnotationBeanPostProcessor 處理——它處理註解,從容器中檢索 JPA Entity Manager 並將其注入。
持久性處理器要麼顯式地通過在配置中定義它來創建,要麼自動創建,通過在命名空間配置中定義 context:annotation-config 或 context:component-scan。
此外,請注意,泛型操作中將 Class 傳遞到構造函數中以進行使用:
@Repository
public class FooDAO extends AbstractJPADAO< Foo > implements IFooDAO{
public FooDAO(){
setClazz(Foo.class );
}
}4. 結論
本教程演示瞭如何使用 Spring 和 JPA 設置 DAO 層的方法,同時使用了 XML 和 Java 兩種配置方式。我們還討論了不應使用 JpaTemplate 的原因,以及如何用 EntityManager 來替代它。最終結果是一個輕量級、簡潔的 DAO 實現,幾乎沒有編譯時依賴於 Spring。