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-weaver
XML元素來配置上下文範圍的LoadTimeWeaver
。所有JPALocalContainerEntityManagerFactoryBeans
都會自動拾取這樣的全域性織入器。這是設定載入時間織入器的首選方式,為平臺(WebLogic,GlassFish,Tomcat,Resin,JBoss或VM代理)提供自動檢測功能,並將織入元件自動傳播到所有可以感知織入者的Bean:
<context:load-time-weaver/>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
...
</bean>
開發者也可以通過LocalContainerEntityManagerFactoryBean
的loadTimeWeaver
屬性來手動指定專用的織入器:
<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
例項不是。注入的JPAEntityManager
的行為類似於從JPA Spec中定義的應用程式伺服器的JNDI環境中提取的EntityManager
。它將所有呼叫委託給當前事務的EntityManager
(如果有);否則,它每個操作返回的都是新建立的EntityManager
,通過使用不同的EntityManager
來保證使用時的執行緒安全。
通過注入的方式使用EntityManagerFactory
或EntityManager
來編寫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-config
XML元素。這樣做會自動註冊所有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
)的註解可以應用於類中的例項變數或方法,也就是表示式方法級注入和例項變數級注入。例項變數級註釋簡潔易用,而方法級別允許進一步處理注入的依賴關係。在這兩種情況下,成員的可見性(public
,protected
,private
)並不重要。
類級註解怎麼辦?
在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
作為高階功能,JpaTransactionManager
和AbstractEntityManagerFactoryBean
的子類支援自定義JpaDialect
,將其作為Bean傳遞給jpaDialect
屬性。JpaDialect
實現可以以供應商特定的方式使能Spring支援的一些高階功能:
- 應用特定的事務語義,如自定義隔離級別或事務超時
- 為基於JDBC的DAO匯出事務性JDBC連線
- 從
PersistenceExceptions
到SpringDataAccessExceptions
的異常轉義
這對於特殊的事務語義和異常的高階翻譯特別有價值。但是Spring使用的預設實現(DefaultJpaDialect
)是不提供任何特殊功能的。如果需要上述功能,則必須指定適當的方言才可以。
作為一個更廣泛的供應商適應設施,主要用於Spring的全功能
LocalContainerEntityManagerFactoryBean
設定,JpaVendorAdapter
將JpaDialect
的功能與其他提供者特定的預設設定相結合。指定HibernateJpaVendorAdapter
或EclipseLinkJpaVendorAdapter
是分別為Hibernate或EclipseLink自動配置EntityManagerFactory
設定的最簡單方便的方法。但是請注意,這些提供程式介面卡主要是為了與Spring驅動的事務管理一起使用而設計的,即為了與JpaTransactionManager
配合使用的。
有關其操作的更多詳細資訊以及在Spring的JPA支援中如何使用,請參閱JpaDialect
和JpaVendorAdapter
的Javadoc。
為JPA配置JTA事務管理
作為JpaTransactionManager
的替代方案,Spring還允許通過JTA在J2EE環境中或與獨立的事務協調器(如Atomikos)進行多資源事務協調。除了用Spring的JtaTransactionManager
替換JpaTransactionManager
,還有需要以下一些操作:
- 底層JDBC連線池是需要具備XA功能,並與開發者的事務協調器整合的。這在J2EE環境中很簡單,只需通過JNDI匯出不同型別的
DataSource
即可。有關匯出DataSource
等詳細資訊,可以參考應用伺服器文件。類似地,獨立的事務協調器通常帶有特殊的XA整合的DataSource
實現。 - 需要為JTA配置JPA
EntityManagerFactory
。這是特定於提供程式的,通常通過在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專案的一部分,該專案旨在為新