閱讀741 返回首頁    go 阿裏雲 go 技術社區[雲棲]


《Spring 5 官方文檔》16.ORM和數據訪問(三)

16.4.2 基於JPA的EntityManagerFactory和EntityManager來實現DAO

雖然EntityManagerFactory實例是線程安全的,但EntityManager實例不是。注入的JPA EntityManager的行為類似於從JPA Spec中定義的應用程序服務器的JNDI環境中提取的EntityManager。它將所有調用委托給當前事務的EntityManager(如果有);否則,它每個操作返回的都是新創建的EntityManager,通過使用不同的EntityManager來保證使用時的線程安全。

通過注入的方式使用EntityManagerFactoryEntityManager來編寫JPA代碼,是不需要依賴任何Spring定義的類的。如果啟用了PersistenceAnnotationBeanPostProcessor,Spring可以在實例級別和方法級別識別@PersistenceUnit@PersistenceContext注解。使用@PersistenceUnit注解的純JPA DAO實現可能如下所示:

  1. public class ProductDaoImpl implements ProductDao {
  2. private EntityManagerFactory emf;
  3. @PersistenceUnit
  4. public void setEntityManagerFactory(EntityManagerFactory emf) {
  5. this.emf = emf;
  6. }
  7. public Collection loadProductsByCategory(String category) {
  8. EntityManager em = this.emf.createEntityManager();
  9. try {
  10. Query query = em.createQuery("from Product as p where p.category = ?1");
  11. query.setParameter(1, category);
  12. return query.getResultList();
  13. }
  14. finally {
  15. if (em != null) {
  16. em.close();
  17. }
  18. }
  19. }
  20. }

上麵的DAO對Spring的實現是沒有任何依賴的,而且很適合與Spring的應用程序上下文進行集成。而且,DAO還可以通過注解來注入默認的EntityManagerFactory

  1. <beans>
  2. <!-- bean post-processor for JPA annotations -->
  3. <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
  4. <bean id="myProductDao" class="product.ProductDaoImpl"/>
  5. </beans>

如果不想明確定義PersistenceAnnotationBeanPostProcessor,可以考慮在應用程序上下文配置中使用Spring上下文annotation-configXML元素。這樣做會自動注冊所有Spring標準後置處理器,用於初始化基於注解的配置,包括CommonAnnotationBeanPostProcessor等。

  1. <beans>
  2. <!-- post-processors for all standard config annotations -->
  3. <context:annotation-config/>
  4. <bean id="myProductDao" class="product.ProductDaoImpl"/>
  5. </beans>

這樣的DAO的主要問題是它總是通過工廠創建一個新的EntityManager。開發者可以通過請求事務性EntityManager(也稱為共享EntityManager,因為它是實際的事務性EntityManager的一個共享的,線程安全的代理)來避免這種情況。

  1. public class ProductDaoImpl implements ProductDao {
  2. @PersistenceContext
  3. private EntityManager em;
  4. public Collection loadProductsByCategory(String category) {
  5. Query query = em.createQuery("from Product as p where p.category = :category");
  6. query.setParameter("category", category);
  7. return query.getResultList();
  8. }
  9. }

@PersistenceContext注解具有可選的屬性類型,默認值為PersistenceContextType.TRANSACTION。此默認值是開發者所需要接收共享的EntityManager代理。替代方案PersistenceContextType.EXTENDED則完全不同:該方案會返回一個所謂擴展的EntityManager,該EntityManager不是線程安全的,因此不能在並發訪問的組件(如Spring管理的單例Bean)中使用。擴展實體管理器僅應用於狀態組件中,比如持有會話的組件,其中EntityManager的生命周期與當前事務無關,而是完全取決於應用程序。

方法和實例變量級別注入

指示依賴注入(例如@PersistenceUnit@PersistenceContext)的注解可以應用於類中的實例變量或方法,也就是表達式方法級注入和實例變量級注入。實例變量級注釋簡潔易用,而方法級別允許進一步處理注入的依賴關係。在這兩種情況下,成員的可見性(publicprotectedprivate)並不重要。

類級注解怎麼辦?

在J2EE平台上,它們用於依賴關係聲明,而不是資源注入。

注入的EntityManager是由Spring管理的(Spring可以意識到正在進行的事務)。重要的是要注意,因為通過注解進行注入,即使新的DAO實現使用通過方法注入的EntityManager而不是EntityManagerFactory的注入的,在應用程序上下文XML中不需要進行任何修改。

這種DAO風格的主要優點是它隻依賴於Java Persistence API;不需要導入任何Spring的實現類。而且,Spring容器可以識別JPA注解來實現自動的注入和管理。從非侵入的角度來看,這種風格對JPA開發者來說可能更為自然。

16.4.3 Spring驅動的JPA事務

如果開發者還沒有閱讀聲明式事務管理,強烈建議開發者先行閱讀,這樣可以更詳細地了解Spring的對聲明式事務支持。

JPA的推薦策略是通過JPA的本地事務支持的本地事務。 Spring的JpaTransactionManager提供了許多來自本地JDBC事務的功能,例如針對任何常規JDBC連接池(不需要XA要求)指定事務的隔離級別和資源級隻讀優化等。

Spring JPA還允許配置JpaTransactionManager將JPA事務暴露給訪問同一DataSource的JDBC訪問代碼,前提是注冊的JpaDialect支持檢索底層JDBC連接。Spring為EclipseLink和Hibernate JPA實現提供了實現。有關JpaDialect機製的詳細信息,請參閱下一節。

16.4.4 JpaDialect和JpaVendorAdapter

作為高級功能,JpaTransactionManagerAbstractEntityManagerFactoryBean的子類支持自定義JpaDialect,將其作為Bean傳遞給jpaDialect屬性。JpaDialect實現可以以供應商特定的方式使能Spring支持的一些高級功能:

  • 應用特定的事務語義,如自定義隔離級別或事務超時
  • 為基於JDBC的DAO導出事務性JDBC連接
  • PersistenceExceptions到SpringDataAccessExceptions的異常轉義

這對於特殊的事務語義和異常的高級翻譯特別有價值。但是Spring使用的默認實現(DefaultJpaDialect)是不提供任何特殊功能的。如果需要上述功能,則必須指定適當的方言才可以。

作為一個更廣泛的供應商適應設施,主要用於Spring的全功能LocalContainerEntityManagerFactoryBean設置,JpaVendorAdapterJpaDialect的功能與其他提供者特定的默認設置相結合。指定HibernateJpaVendorAdapterEclipseLinkJpaVendorAdapter是分別為Hibernate或EclipseLink自動配置EntityManagerFactory設置的最簡單方便的方法。但是請注意,這些提供程序適配器主要是為了與Spring驅動的事務管理一起使用而設計的,即為了與JpaTransactionManager配合使用的。

有關其操作的更多詳細信息以及在Spring的JPA支持中如何使用,請參閱JpaDialectJpaVendorAdapter的Javadoc。

16.4.5 為JPA配置JTA事務管理

作為JpaTransactionManager的替代方案,Spring還允許通過JTA在J2EE環境中或與獨立的事務協調器(如Atomikos)進行多資源事務協調。除了用Spring的JtaTransactionManager替換JpaTransactionManager,還有需要以下一些操作:

  • 底層JDBC連接池是需要具備XA功能,並與開發者的事務協調器集成的。這在J2EE環境中很簡單,隻需通過JNDI導出不同類型的DataSource即可。有關導出DataSource等詳細信息,可以參考應用服務器文檔。類似地,獨立的事務協調器通常帶有特殊的XA集成的DataSource實現。
  • 需要為JTA配置JPAEntityManagerFactory。這是特定於提供程序的,通常通過在LocalContainerEntityManagerFactoryBean的特殊屬性指定為”jpaProperties”。在使用Hibernate的情況下,這些屬性甚至是需要基於特定的版本的;請查閱Hibernate文檔以獲取詳細信息。
  • Spring的HibernateJpaVendorAdapter會強製執行某些麵向Spring的默認設置,例如在Hibernate 5.0中匹配Hibernate自己的默認值的連接釋放模式“on-close”,但在5.1 / 5.2中不再存在。對於JTA設置,不要聲明HibernateJpaVendorAdapter開始,或關閉其prepareConnection標誌。或者,將Hibernate 5.2的hibernate.connection.handling_mode屬性設置為DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT以恢複Hibernate自己的默認值。有關WebLogic的相關說明,請參考Hibernate的虛假應用服務器警告一節。
  • 或者,可以考慮從應用程序服務器本身獲取EntityManagerFactory,即通過JNDI查找而不是本地聲明的LocalContainerEntityManagerFactoryBean。服務器提供的EntityManagerFactory可能需要在服務器配置中進行特殊定義,減少了部署的移植性,但是EntityManagerFactory將為開箱即用的服務器JTA環境設置。
轉載自 並發編程網 - ifeve.com  

最後更新:2017-05-18 10:33:01

  上一篇:go  寫一個簡單的工作流(三)
  下一篇:go  寫一個簡單的工作流(二)