1. 程式人生 > >Spring ORM資料訪問——JPA

Spring ORM資料訪問——JPA

JPA

Spring JPA在org.springframework.orm.jpa包中已經可用,Spring JPA用了Hibernate整合相似的方法來提供更易於理解的JPA支援,與此同時,瞭解了JPA底層實現,可以理解更多的Spring JPA特性。

Spring中JPA配置的三個選項

Spring JPA支援提供了三種配置JPAEntityManagerFactory的方法,之後通過EntityManagerFactory來獲取對應的實體管理器。

LocalEntityManagerFactoryBean

通常只有在簡單的部署環境中使用此選項,例如在獨立應用程式或者進行整合測試時,才會使用這種方式。

LocalEntityManagerFactoryBean建立一個適用於應用程式且僅使用JPA進行資料訪問的簡單部署環境的EntityManagerFactory。工廠bean會使用JPAPersistenceProvider自動檢測機制,並且在大多數情況下,僅要求開發者指定持久化單元的名稱:

<beans>
    <bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName"
value="myPersistenceUnit"/>
</bean> </beans>

這種形式的JPA部署是最簡單的,同時限制也很多。開發者不能引用現有的JDBCDataSource bean定義,並且不支援全域性事務。而且,持久化類的織入(weaving)(位元組碼轉換)是特定於提供者的,通常需要在啟動時指定特定的JVM代理。該選項僅適用於符合JPA Spec的獨立應用程式或測試環境。

從JNDI中獲取EntityManagerFactory

在部署到J2EE伺服器時可以使用此選項。檢查伺服器的文件來了解如何將自定義JPA提供程式部署到伺服器中,從而對伺服器進行比預設更多的個性化定製。

從JNDI獲取EntityManagerFactory(例如在Java EE環境中),只需要在XML配置中加入配置資訊即可:

<beans>
    <jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/>
</beans>

此操作將採用標準J2EE引導:J2EE伺服器自動檢測J2EE部署描述符(例如web.xml)中persistence-unit-ref條目和永續性單元(實際上是應用程式jar中的META-INF/persistence.xml檔案),併為這些永續性單元定義環境上下文位置。

在這種情況下,整個持久化單元部署(包括持久化類的織入(weaving)(位元組碼轉換))都取決於J2EE伺服器。JDBC DataSource通過META-INF/persistence.xml檔案中的JNDI位置進行定義; 而EntityManager事務與伺服器JTA子系統整合。 Spring僅使用獲取的EntityManagerFactory,通過依賴注入將其傳遞給應用程式物件,通常通過JtaTransactionManager來管理永續性單元的事務。

如果在同一應用程式中使用多個永續性單元,則這種JNDI檢索的永續性單元的bean名稱應與應用程式用於引用它們的永續性單元名稱相匹配,例如@PersistenceUnit@PersistenceContext註釋。

LocalContainerEntityManagerFactoryBean

在基於Spring的應用程式環境中使用此選項來實現完整的JPA功能。這包括諸如Tomcat的Web容器,以及具有複雜永續性要求的獨立應用程式和整合測試。

LocalContainerEntityManagerFactoryBean可以完全控制EntityManagerFactory的配置,同時適用於需要細粒度定製的環境。 LocalContainerEntityManagerFactoryBean會基於persistence.xml檔案,dataSourceLookup策略和指定的loadTimeWeaver來建立一個PersistenceUnitInfo例項。因此,可以在JNDI之外使用自定義資料來源並控制織入(weaving)過程。以下示例顯示LocalContainerEntityManagerFactoryBean的典型Bean定義:

<beans>
    <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="someDataSource"/>
        <property name="loadTimeWeaver">
            <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
        </property>
    </bean>
</beans>

下面的例子是一個典型的persistence.xml檔案:

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
    <persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
        <mapping-file>META-INF/orm.xml</mapping-file>
        <exclude-unlisted-classes/>
    </persistence-unit>
</persistence>

<exclude-unlisted-classes />標籤表示不會進行註解實體類的掃描。指定的顯式true值 - <exclude-unlisted-classes>true</exclude-unlisted-classes/>- 也意味著不進行掃描。<exclude-unlisted-classes> false</exclude-unlisted-classes>則會觸發掃描;但是,如果開發者需要進行實體類掃描,建議開發者簡單地省略<exclude-unlisted-classes>元素。

LocalContainerEntityManagerFactoryBean是最強大的JPA設定選項,允許在應用程式中進行靈活的本地配置。它支援連線到現有的JDBCDataSource,支援本地和全域性事務等。但是,它對執行時環境施加了需求,其中之一就是如果永續性提供程式需要位元組碼轉換,就需要有織入(weaving)能力的類載入器。

此選項可能與J2EE伺服器的內建JPA功能衝突。在完整的J2EE環境中,請考慮從JNDI獲取EntityManagerFactory。或者,在開發者的LocalContainerEntityManagerFactoryBean定義中指定一個自定義persistenceXmlLocation,例如META-INF/my-persistence.xml,並且只在應用程式jar檔案中包含有該名稱的描述符。因為J2EE伺服器僅查詢預設的META-INF/persistence.xml檔案,所以它會忽略這種自定義永續性單元,從而避免了與Spring驅動的JPA設定之間發生衝突。 (例如,這適用於Resin 3.1)

何時需要載入時間織入?
並非所有JPA提供商都需要JVM代理。Hibernate就是一個不需要JVM代理的例子。如果開發者的提供商不需要代理或開發者有其他替代方案,例如通過定製編譯器或Ant任務在構建時應用增強功能,則不用使用載入時間編織器。

LoadTimeWeaver是一個Spring提供的介面,它允許以特定方式插入JPAClassTransformer例項,這取決於環境是Web容器還是應用程式伺服器。 通過代理掛載ClassTransformers通常效能較差。代理會對整個虛擬機器進行操作,並檢查載入的每個類,這是生產伺服器環境中最不需要的額外負載。

Spring為各種環境提供了一些LoadTimeWeaver實現,允許ClassTransformer例項僅適用於每個類載入器,而不是每個VM。

有關LoadTimeWeaver的實現及其設定的通用或定製的各種平臺(如Tomcat,WebLogic,GlassFish,Resin和JBoss)的更多瞭解,請參閱AOP章節中的Spring配置一節。

如前面部分所述,開發者可以使用@EnableLoadTimeWeaving註解或者load-time-weaverXML元素來配置上下文範圍的LoadTimeWeaver。所有JPALocalContainerEntityManagerFactoryBeans都會自動拾取這樣的全域性織入器。這是設定載入時間織入器的首選方式,為平臺(WebLogic,GlassFish,Tomcat,Resin,JBoss或VM代理)提供自動檢測功能,並將織入元件自動傳播到所有可以感知織入者的Bean:

<context:load-time-weaver/>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    ...
</bean>

開發者也可以通過LocalContainerEntityManagerFactoryBeanloadTimeWeaver屬性來手動指定專用的織入器:

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="loadTimeWeaver">
        <bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
    </property>
</bean>

無論LTW如何配置,使用這種技術,依賴於儀器的JPA應用程式都可以在目標平臺(例如:Tomcat)中執行,而不需要代理。這尤其重要的是當主機應用程式依賴於不同的JPA實現時,因為JPA轉換器僅應用於類載入器級,彼此隔離。

處理多個持久化單元

例如,對於依賴儲存在類路徑中的各種JARS中的多個永續性單元位置的應用程式,Spring將PersistenceUnitManager作為中央倉庫來避免可能昂貴的永續性單元發現過程。預設實現允許指定多個位置,這些位置將通過永續性單元名稱進行解析並稍後檢索。(預設情況下,搜尋classpath下的META-INF/persistence.xml檔案。)

<bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
    <property name="persistenceXmlLocations">
        <list>
            <value>org/springframework/orm/jpa/domain/persistence-multi.xml</value>
            <value>classpath:/my/package/**/custom-persistence.xml</value>
            <value>classpath*:META-INF/persistence.xml</value>
        </list>
    </property>
    <property name="dataSources">
        <map>
            <entry key="localDataSource" value-ref="local-db"/>
            <entry key="remoteDataSource" value-ref="remote-db"/>
        </map>
    </property>
    <!-- if no datasource is specified, use this one -->
    <property name="defaultDataSource" ref="remoteDataSource"/>
</bean>

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitManager" ref="pum"/>
    <property name="persistenceUnitName" value="myCustomUnit"/>
</bean>

在預設實現傳遞給JPA provider之前,是允許通過屬性(影響全部持久化單元)或者通過PersistenceUnitPostProcessor以程式設計(對選擇的持久化單元進行)進行對PersistenceUnitInfo進行自定義的。如果沒有指定PersistenceUnitManager,則由LocalContainerEntityManagerFactoryBean在內部建立和使用。

基於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實現可能如下所示:

public class ProductDaoImpl implements ProductDao {

    private EntityManagerFactory emf;

    @PersistenceUnit
    public void setEntityManagerFactory(EntityManagerFactory emf) {
        this.emf = emf;
    }

    public Collection loadProductsByCategory(String category) {
        EntityManager em = this.emf.createEntityManager();
        try {
            Query query = em.createQuery("from Product as p where p.category = ?1");
            query.setParameter(1, category);
            return query.getResultList();
        }
        finally {
            if (em != null) {
                em.close();
            }
        }
    }
}

上面的DAO對Spring的實現是沒有任何依賴的,而且很適合與Spring的應用程式上下文進行整合。而且,DAO還可以通過註解來注入預設的EntityManagerFactory

<beans>

    <!-- bean post-processor for JPA annotations -->
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

    <bean id="myProductDao" class="product.ProductDaoImpl"/>
</beans>

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

<beans>
    <!-- post-processors for all standard config annotations -->
    <context:annotation-config/>

    <bean id="myProductDao" class="product.ProductDaoImpl"/>
</beans>

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

public class ProductDaoImpl implements ProductDao {

    @PersistenceContext
    private EntityManager em;

    public Collection loadProductsByCategory(String category) {
        Query query = em.createQuery("from Product as p where p.category = :category");
        query.setParameter("category", category);
        return query.getResultList();
    }
}

@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開發者來說可能更為自然。

Spring驅動的JPA事務

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

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

Spring JPA還允許配置JpaTransactionManager將JPA事務暴露給訪問同一DataSource的JDBC訪問程式碼,前提是註冊的JpaDialect支援檢索底層JDBC連線。Spring為EclipseLink和Hibernate JPA實現提供了實現。有關JpaDialect機制的詳細資訊,請參閱下一節。

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。

為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環境設定。

相關推薦

Spring ORM資料訪問——JPA

JPA Spring JPA在org.springframework.orm.jpa包中已經可用,Spring JPA用了Hibernate整合相似的方法來提供更易於理解的JPA支援,與此同時,瞭解了JPA底層實現,可以理解更多的Spring JPA特性。

Spring Boot(三)——Spring Boot資料訪問

一、簡介 對於資料訪問層,無論是SQL還是NOSQL,Spring Boot預設採用整合Spring Data的方式進行統一處理,新增大量自動配置,遮蔽了很多設定。引入各種xxxTemplate,xxxRepository來簡化我們對資料訪問層的操作。對我們來說只需要進行簡單的設定即

Spring資料訪問---------------事務管理

ThreadLocal   ThreadLocal為每一個使用該變數的執行緒分配一個變數副本,所以每一個執行緒在改變自己的副本時,不會改變其他執行緒的副本資訊。該類主要包含四個方法:   public void set(Object obj)   public Object get()   publi

Spring-JDBC 資料訪問

新增.jar包 <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <dependency> <groupId>org

Spring系列學習之Spring Data 資料訪問介紹

英文原文:https://spring.io/projects/spring-data 概述 Spring Data的使命是為資料訪問提供熟悉且一致的基於Spring的程式設計模型,同時仍保留底層資料儲存的特殊特性。它使得使用資料訪問技術,關係資料庫和非關係資料庫,map-reduce框架和

一個類GraphQL的ORM資料訪問框架釋出

Zongsoft.Data 釋出公告 很高興我們的 ORM 資料訪問框架(Zongsoft.Data)在歷經兩個 SaaS 產品的應用之後,今天正式宣佈對外推廣! 這是一個類 GraphQL 風格的 ORM(Object/Relational Mapping)

06.深入淺出 Spring Boot - 資料訪問之Druid

程式碼下載:https://github.com/Jackson0714/study-spring-boot.git 05. 深入淺出 Spring Boot - 資料訪問之JDBC(原始碼分析+程式碼下載) 06. 深入淺出 Spring Boot - 資料訪問之Druid(附程式碼下載) 一、Dru

Spring Boot簡明教程之資料訪問(二):JPA(超詳細)

Spring Boot簡明教程之資料訪問(二):JPA(超詳細) 文章目錄 Spring Boot簡明教程之資料訪問(二):JPA(超詳細) 建立專案 Spring Data簡介 JPA簡介 Spring Data 與JP

Spring Boot 基礎系列教程 | 第十二篇:使用Spring-data-jpa簡化資料訪問層(推薦)

推薦 Spring Boot/Cloud 視訊: Spring Boot中使用Spring-data-jpa讓資料訪問更簡單、更優雅 在上一篇Spring中使用JdbcTemplate訪問資料庫 中介紹了一種基本的資料訪問方式,結合構建RESTful API和

Spring Boot中使用Spring-data-jpa資料訪問更簡單、更優雅

在上一篇Spring中使用JdbcTemplate訪問資料庫 中介紹了一種基本的資料訪問方式,結合構建RESTful API、使用Thymeleaf模板引擎渲染Web檢視的內容就已經可以完成App服務端和Web站點的開發任務了。  然而,在實際開發過程中,對資料庫的操作

Spring系列學習之Spring Data JPA資料訪問

英文原文:https://spring.io/projects/spring-data-jpa   概述 Spring Data JPA是更大的Spring Data系列的一部分,可以輕鬆實現基於JPA的儲存庫。此模組處理對基於JPA的資料訪問層的增強支援。它使構建使用資料訪問

Spring 5 官方文件》16.ORM資料訪問

16.3 Hibernate 我們將首先介紹Spring環境中的Hibernate 5,然後通過使用Hibernate 5來演示Spring整合O-R對映器的方法。本節將詳細介紹許多問題,並顯示DAO實現和事務劃分的不同變體。這些模式中大多數可以直接轉換為所有其他支援的ORM工具。本章中的以下部分將通過簡

微服務:Spring Boot第三篇——資料訪問Spring Data JPA

這篇要從HelloWorld進一步,實現從資料庫中取資料,然後顯示在web頁面上的功能,資料庫採用H2,這是一種嵌入式的資料庫,無需安裝獨立的客戶端或者伺服器端。 Hibernate是一種使用物件關係對映(Object-Relational Mapping)實現資料訪問和操作的技術,它將

SpringCloud SpringBoot mybatis 分散式微服務(九)Spring Boot中使用Spring-data-jpa資料訪問更簡單

然而,在實際開發過程中,對資料庫的操作無非就“增刪改查”。就最為普遍的單表操作而言,除了表和欄位不同外,語句都是類似的,開發人員需要寫大量類似而枯燥的語句來完成業務邏輯。為了解決這些大量枯燥的資料操作語句,我們第一個想到的是使用ORM框架,比如:Hibernate。通過整合H

spring面試題(三):註解+資料訪問

Spring註解 1. 什麼是基於Java的Spring註解配置? 給一些註解的例子. 基於Java的配置,允許你在少量的Java註解的幫助下,進行你的大部分Spring配置而非通過XML檔案。 以@Configuration 註解為例,它用來標記類可以當做

Spring Boot簡明教程之資料訪問(三):MyBatis

Spring Boot簡明教程之資料訪問(三):MyBatis 文章目錄 Spring Boot簡明教程之資料訪問(三):MyBatis MyBatis簡介 使用註解進行資料訪問 專案建立 專案目錄

十五、SpringBoot之資料訪問整合SpringData JPA

1.SpringData簡介 2.整合SpringData JPA JPA:ORM(Object Relational Mapping 物件關係對映); 1.編寫一個實體類(bean)和資料表

spring-boot-SpringBoot與資料訪問

1.JDBC (1).匯入依賴 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc

Spring系列學習之Spring Data Apache Hadoop資料訪問

英文原文:https://spring.io/projects/spring-hadoop 目錄 概述 介紹 特性 版本和分發支援 Spring Boot 配置 快速開始 學習 文件 示例 概述 注意:Spring for Apache Hadoo

Spring系列學習之Spring Data Elasticsearch資料訪問

英文原文:https://spring.io/projects/spring-data-elasticsearch 目錄 概述 特性 快速開始 學習 文件 概述 Elasticsearch的Spring Data是Spring Data專案的一部分,該專案旨在為新