http://www.ibm.com/developerworks/cn/opensource/os-cn-spring-jpa/
一般情況下,會在項目啟動的過程中,自動檢查注解的實體和數據表,如果數據庫不存在的標,會根據實體自動生成
首先,讓持久層接口 UserDao 繼承 Repository 接口。該接口使用了泛型,需要為其提供兩個類型:第一個為該接口處理的域對象類型,第二個為該域對象的主鍵類型。修改后的 UserDao 如下:
清單 12. Spring Data JPA 風格的持久層接口
public interface UserDao extends Repository<AccountInfo, Long> {
public AccountInfo save(AccountInfo accountInfo);
}
然后刪除 UserDaoImpl 類,因為我們前面說過,框架會為我們完成業務邏輯。最后,我們需要在 Spring 配置文件中增加如下配置,以使 Spring 識別出需要為其實現的持久層接口:
清單 13. 在 Spring 配置文件中啟用掃描並自動創建代理的功能
<-- 需要在 <beans> 標簽中增加對 jpa 命名空間的引用 -->
<jpa:repositories base-package="footmark.springdata.jpa.dao"
entity-manager-factory-ref="entityManagerFactory"
transaction-manager-ref="transactionManager"/>
至此便大功告成了!執行一下測試代碼,然后看一下數據庫,新的數據已經如我們預期的添加到表中了。如果要再增加新的持久層業務,比如希望查詢出給 ID 的 AccountInfo 對象,該怎么辦呢?很簡單,在 UserDao 接口中增加一行代碼即可:
清單 14. 修改后的持久層接口,增加一個方法聲明
public interface UserDao extends Repository<AccountInfo, Long> {
public AccountInfo save(AccountInfo accountInfo);
// 你需要做的,僅僅是新增如下一行方法聲明
public AccountInfo findByAccountId(Long accountId);
}
下面總結一下使用 Spring Data JPA 進行持久層開發大致需要的三個步驟:
- 聲明持久層的接口,該接口繼承 Repository,Repository 是一個標記型接口,它不包含任何方法,當然如果有需要,Spring Data 也提供了若干 Repository 子接口,其中定義了一些常用的增刪改查,以及分頁相關的方法。
- 在接口中聲明需要的業務方法。Spring Data 將根據給定的策略(具體策略稍后講解)來為其生成實現代碼。
- 在 Spring 配置文件中增加一行聲明,讓 Spring 為聲明的接口創建代理對象。配置了 <jpa:repositories> 后,Spring 初始化容器時將會掃描 base-package 指定的包目錄及其子目錄,為繼承 Repository 或其子接口的接口創建代理對象,並將代理對象注冊為 Spring Bean,業務層便可以通過 Spring 自動封裝的特性來直接使用該對象。
此外,<jpa:repository> 還提供了一些屬性和子標簽,便於做更細粒度的控制。可以在 <jpa:repository> 內部使用 <context:include-filter>、<context:exclude-filter> 來過濾掉一些不希望被掃描到的接口。具體的使用方法見 Spring參考文檔。
使用 @Query 創建查詢
@Query 注解的使用非常簡單,只需在聲明的方法上面標注該注解,同時提供一個 JP QL 查詢語句即可,如下所示:
清單 16. 使用 @Query 提供自定義查詢語句示例
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 中的命名參數對應,示例如下:
清單 17. @Query 支持命名參數示例
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 來將該操作標識為修改查詢,這樣框架最終會生成一個更新的操作,而非查詢。如下所示:
清單 18. 使用 @Modifying 將查詢標識為修改查詢
@Modifying
@Query("update AccountInfo a set a.salary = ?1 where a.salary < ?2")
public int increaseSalary(int after, int before);
Spring Data JPA 對事務的支持
默認情況下,Spring Data JPA 實現的方法都是使用事務的。針對查詢類型的方法,其等價於 @Transactional(readOnly=true);增刪改類型的方法,等價於 @Transactional。可以看出,除了將查詢的方法設為只讀事務外,其他事務屬性均采用默認值。
如果用戶覺得有必要,可以在接口方法上使用 @Transactional 顯式指定事務屬性,該值覆蓋 Spring Data JPA 提供的默認值。同時,開發者也可以在業務層方法上使用 @Transactional 指定事務屬性,這主要針對一個業務層方法多次調用持久層方法的情況。持久層的事務會根據設置的事務傳播行為來決定是掛起業務層事務還是加入業務層的事務。具體 @Transactional 的使用,請參考 Spring的參考文檔。