轉自:
http://www.cnblogs.com/WangJinYang/p/4257383.htmlhtml
自 JPA 伴隨 Java EE 5 發佈以來,受到了各大廠商及開源社區的追捧,各類商用的和開源的 JPA 框架如雨後春筍般出現,爲開發者提供了豐富的選擇。它一改以前 EJB 2.x 中實體 Bean 笨重且難以使用的形象,充分吸取了在開源社區已經相對成熟的 ORM 思想。另外,它並不依賴於 EJB 容器,能夠做爲一個獨立的持久層技術而存在。目前比較成熟的 JPA 框架主要包括 Jboss 的 Hibernate EntityManager、Oracle 捐獻給 Eclipse 社區的 EclipseLink、Apache 的 OpenJPA 等。java
Java 持久化規範,是從EJB2.x之前的實體Bean(Entity bean)分離出來的,EJB3之後再也不有實體bean,而是將實體bean放到JPA中實現。JPA是sun提出的一個對象持久化規範,各JavaEE 應用服務器自主選擇具體實現,JPA的設計者是Hibernate框架的做者,所以Hibernate做爲Jboss服務器中JPA的默認實 現,Oracle的Weblogic使用EclipseLink(之前叫TopLink)做爲默認的JPA實現,IBM的Websphere和Sun的 Glassfish默認使用OpenJPA(Apache的一個開源項目)做爲其默認的JPA實現。
JPA的底層實現是一些流行的開源ORM(對象關係映射)框架,所以JPA其實也就是java實體對象和關係型數據庫創建起映射關係,經過面向對象編程的思想操做關係型數據庫的規範。spring
Spring 框架對 JPA 提供的支持主要體如今以下幾個方面:數據庫
首先,它使得 JPA 配置變得更加靈活。JPA 規範要求,配置文件必須命名爲 persistence.xml,並存在於類路徑下的 META-INF 目錄中。該文件一般包含了初始化 JPA 引擎所需的所有信息。Spring 提供的 LocalContainerEntityManagerFactoryBean 提供了很是靈活的配置,persistence.xml 中的信息均可以在此以屬性注入的方式提供。編程
第三,也是最具意義的,Spring 將 EntityManager 的建立與銷燬、事務管理等代碼抽取出來,並由其統一管理,開發者不須要關心這些,業務方法中只剩下操做領域對象的代碼,事務管理和 EntityManager 建立、銷燬的代碼都再也不須要開發者關心了。數組
Spring Data JPA 框架,主要針對的就是 Spring 惟一沒有簡化到的業務邏輯代碼,至此,開發者連僅剩的實現持久層業務邏輯的工做都省了,惟一要作的,就只是聲明持久層的接口,其餘都交給 Spring Data JPA 來幫你完成!服務器
下面就來了解Spring Data JPA。框架
1.下載須要的包。dom
須要先 下載Spring Data JPA 的發佈包(須要同時下載 Spring Data Commons 和 Spring Data JPA 兩個發佈包,Commons 是 Spring Data 的公共基礎包),並把相關的依賴 JAR 文件加入到 CLASSPATH 中。post
2.讓持久層接口 Dao(以UserDao) 繼承 Repository 接口。
該接口使用了泛型,須要爲其提供兩個類型:第一個爲該接口處理的域對象類型,第二個爲該域對象的主鍵類型。 以下:
Spring Data JPA 風格的持久層接口:
public interface UserDao extends Repository<AccountInfo, Long> { public AccountInfo save(AccountInfo accountInfo); }
不須要UserDao的實現類,框架會爲咱們完成業務邏輯。
3.在 Spring 配置文件中啓用掃描並自動建立代理的功能。
<-- 須要在 <beans> 標籤中增長對 jpa 命名空間的引用 --> <jpa:repositories base-package="footmark.springdata.jpa.dao" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager"/>
4.測試代碼。
public interface UserDao extends Repository<AccountInfo, Long> { public AccountInfo save(AccountInfo accountInfo); // 你須要作的,僅僅是新增以下一行方法聲明 public AccountInfo findByAccountId(Long accountId); }
5.總結
使用 Spring Data JPA 進行持久層開發大體須要的三個步驟:
1.聲明持久層的接口,該接口繼承 Repository,Repository 是一個標記型接口,它不包含任何方法,固然若是有須要,Spring Data 也提供了若干 Repository 子接口,其中定義了一些經常使用的增刪改查,以及分頁相關的方法。
2.在接口中聲明須要的業務方法。Spring Data 將根據給定的策略來爲其生成實現代碼。
3. 在 Spring 配置文件中增長一行聲明,讓 Spring 爲聲明的接口建立代理對象。配置了 <jpa:repositories> 後,Spring 初始化容器時將會掃描 base-package 指定的包目錄及其子目錄,爲繼承 Repository 或其子接口的接口建立代理對象,並將代理對象註冊爲 Spring Bean,業務層即可以經過 Spring 自動封裝的特性來直接使用該對象。
此 外,<jpa:repository> 還提供了一些屬性和子標籤,便於作更細粒度的控制。能夠在 <jpa:repository> 內部使用 <context:include-filter>、<context:exclude-filter> 來過濾掉一些不但願被掃描到的接口。
持 久層接口繼承 Repository 並非惟一選擇。Repository 接口是 Spring Data 的一個核心接口,它不提供任何方法,開發者須要在本身定義的接口中聲明須要的方法。與繼承 Repository 等價的一種方式,就是在持久層接口上使用 @RepositoryDefinition 註解,併爲其指定 domainClass 和 idClass 屬性。以下兩種方式是徹底等價的:
兩種等價的繼承接口方式示例:
public interface UserDao extends Repository<AccountInfo, Long> { …… } @RepositoryDefinition(domainClass = AccountInfo.class, idClass = Long.class) public interface UserDao { …… }
1. 若是持久層接口較多,且每個接口都須要聲明類似的增刪改查方法,直接繼承 Repository 就顯得有些囉嗦,這時能夠繼承 CrudRepository,它會自動爲域對象建立增刪改查方法,供業務層直接使用。開發者只是多寫了 "Crud" 四個字母,即刻便爲域對象提供了開箱即用的十個增刪改查方法。
2.使用 CrudRepository 也有反作用,它可能暴露了你不但願暴露給業務層的方法。好比某些接口你只但願提供增長的操做而不但願提供刪除的方法。針對這種狀況,開發者只能退回到 Repository 接口,而後到 CrudRepository 中把但願保留的方法聲明覆制到自定義的接口中便可.
3.分頁查詢和排 序是持久層經常使用的功能,Spring Data 爲此提供了 PagingAndSortingRepository 接口,它繼承自 CrudRepository 接口,在 CrudRepository 基礎上新增了兩個與分頁有關的方法。可是,咱們不多會將自定義的持久層接口直接繼承自 PagingAndSortingRepository,而是在繼承 Repository 或 CrudRepository 的基礎上,在本身聲明的方法參數列表最後增長一個 Pageable 或 Sort 類型的參數,用於指定分頁或排序信息便可,這比直接使用 PagingAndSortingRepository 提供了更大的靈活性。
4.JpaRepository 是繼承自 PagingAndSortingRepository 的針對 JPA 技術提供的接口,它在父接口的基礎上,提供了其餘一些方法,好比 flush(),saveAndFlush(),deleteInBatch() 等。若是有這樣的需求,則能夠繼承該接口。
1.經過解析方法名建立查詢
框 架在進行方法名解析時,會先把方法名多餘的前綴截取掉,好比 find、findBy、read、readBy、get、getBy,而後對剩下部分進行解析。而且若是方法的最後一個參數是 Sort 或者 Pageable 類型,也會提取相關的信息,以便按規則進行排序或者分頁查詢。
在建立查詢時,咱們經過在方法名中使用屬性名稱來表達,好比 findByUserAddressZip ()。框架在解析該方法時,首先剔除 findBy,而後對剩下的屬性進行解析,詳細規則以下(此處假設該方法針對的域對象爲 AccountInfo 類型):
在查詢時,一般須要同時根據多個屬性進行查詢,且查詢的條件也格式各樣(大於某個值、在某個範圍等等),Spring Data JPA 爲此提供了一些表達條件查詢的關鍵字,大體以下:
2.使用 @Query 建立查詢
@Query 註解的使用很是簡單,只需在聲明的方法上面標註該註解,同時提供一個 JP QL 查詢語句便可,以下所示:
public interface UserDao extends Repository<AccountInfo, Long> { @Query("select a from AccountInfo a where a.accountId = ?1") public AccountInfo findByAccountId(Long accountId); @Query("select a from AccountInfo a where a.balance > ?1") public Page<AccountInfo> findByBalanceGreaterThan( Integer balance,Pageable pageable); }
不少開發者在建立 JP QL 時喜歡使用命名參數來代替位置編號,@Query 也對此提供了支持。JP QL 語句中經過": 變量"的格式來指定參數,同時在方法的參數前面使用 @Param 將方法參數與 JP QL 中的命名參數對應,示例以下:
public interface UserDao extends Repository<AccountInfo, Long> { public AccountInfo save(AccountInfo accountInfo); @Query("from AccountInfo a where a.accountId = :id") public AccountInfo findByAccountId(@Param("id")Long accountId); @Query("from AccountInfo a where a.balance > :balance") public Page<AccountInfo> findByBalanceGreaterThan( @Param("balance")Integer balance,Pageable pageable); }
此外,開發者也能夠經過使用 @Query 來執行一個更新操做,爲此,咱們須要在使用 @Query 的同時,用 @Modifying 來將該操做標識爲修改查詢,這樣框架最終會生成一個更新的操做,而非查詢。以下所示:
@Modifying
@Query("update AccountInfo a set a.salary = ?1 where a.salary < ?2") public int increaseSalary(int after, int before);
3.經過調用 JPA 命名查詢語句建立查詢
命 名查詢是 JPA 提供的一種將查詢語句從方法體中獨立出來,以供多個方法共用的功能。Spring Data JPA 對命名查詢也提供了很好的支持。用戶只須要按照 JPA 規範在 orm.xml 文件或者在代碼中使用 @NamedQuery(或 @NamedNativeQuery)定義好查詢語句,惟一要作的就是爲該語句命名時,須要知足」DomainClass.methodName()」的 命名規則。假設定義了以下接口:
public interface UserDao extends Repository<AccountInfo, Long> { ...... public List<AccountInfo> findTop5(); }
若是但願爲 findTop5() 建立命名查詢,並與之關聯,咱們只須要在適當的位置定義命名查詢語句,並將其命名爲 "AccountInfo.findTop5",框架在建立代理類的過程當中,解析到該方法時,優先查找名爲 "AccountInfo.findTop5" 的命名查詢定義,若是沒有找到,則嘗試解析方法名,根據方法名字建立查詢。
默 認狀況下,Spring Data JPA 實現的方法都是使用事務的。針對查詢類型的方法,其等價於 @Transactional(readOnly=true);增刪改類型的方法,等價於 @Transactional。能夠看出,除了將查詢的方法設爲只讀事務外,其餘事務屬性均採用默認值。
若是用戶以爲有必要,能夠在接口方 法上使用 @Transactional 顯式指定事務屬性,該值覆蓋 Spring Data JPA 提供的默認值。同時,開發者也能夠在業務層方法上使用 @Transactional 指定事務屬性,這主要針對一個業務層方法屢次調用持久層方法的狀況。持久層的事務會根據設置的事務傳播行爲來決定是掛起業務層事務仍是加入業務層的事務。 具體 @Transactional 的使用能夠參考Spring的參考文檔。