亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

Spring Data JPA

2024-07-21 02:52:22
字體:
來源:轉載
供稿:網友

從一個簡單的 JPA 示例開始

本文主要講述 SPRing Data JPA,但是為了不至于給 JPA 和 Spring 的初學者造成較大的學習曲線,我們首先從 JPA 開始,簡單介紹一個 JPA 示例;接著重構該示例,并引入 Spring 框架,這兩部分不會涉及過多的篇幅,如果希望能夠深入學習 Spring 和 JPA,可以根據本文最后提供的參考資料進一步學習。

自 JPA 伴隨 java EE 5 發布以來,受到了各大廠商及開源社區的追捧,各種商用的和開源的 JPA 框架如雨后春筍般出現,為開發者提供了豐富的選擇。它一改之前 EJB 2.x 中實體 Bean 笨重且難以使用的形象,充分吸收了在開源社區已經相對成熟的 ORM 思想。另外,它并不依賴于 EJB 容器,可以作為一個獨立的持久層技術而存在。目前比較成熟的 JPA 框架主要包括 Jboss 的 Hibernate EntityManager、Oracle 捐獻給 Eclipse 社區的 EclipseLink、Apache 的 OpenJPA 等。

本文的示例代碼基于 Hibernate EntityManager 開發,但是讀者幾乎不用修改任何代碼,便可以非常容易地切換到其他 JPA 框架,因為代碼中使用到的都是 JPA 規范提供的接口 / 類,并沒有使用到框架本身的私有特性。示例主要涉及七個文件,但是很清晰:業務層包含一個接口和一個實現;持久層包含一個接口、一個實現、一個實體類;另外加上一個 JPA 配置文件和一個測試類。相關類 / 接口代碼如下:

清單 1. 實體類 AccountInfo.java
 @Entity  @Table(name = "t_accountinfo")  public class AccountInfo implements Serializable {  private Long accountId;  private Integer balance;  // 此處省略 getter 和 setter 方法。 }
清單 2. 業務層接口 UserService.java
 public interface UserService {  public AccountInfo createNewAccount(String user, String pwd, Integer init);  }
清單 3. 業務層的實現類 UserServiceImpl.java
 public class UserServiceImpl implements UserService {  private UserDao userDao = new UserDaoImpl();  public AccountInfo createNewAccount(String user, String pwd, Integer init){  // 封裝域對象 AccountInfo accountInfo = new AccountInfo();  UserInfo userInfo = new UserInfo();  userInfo.setUsername(username);  userInfo.setPassWord(password);  accountInfo.setBalance(initBalance);  accountInfo.setUserInfo(userInfo);  // 調用持久層,完成數據的保存 return userDao.save(accountInfo);     }  }
清單 4. 持久層接口
 public interface UserDao {  public AccountInfo save(AccountInfo accountInfo);  }
清單 5. 持久層的實現類
 public class UserDaoImpl implements UserDao {  public AccountInfo save(AccountInfo accountInfo) {  EntityManagerFactory emf =  Persistence.createEntityManagerFactory("SimplePU");  EntityManager em = emf.createEntityManager();  em.getTransaction().begin();  em.persist(accountInfo);  em.getTransaction().commit();  emf.close();  return accountInfo;     }  }
清單 6. JPA 標準配置文件 persistence.xml
 <?xml version="1.0" encoding="UTF-8"?>  <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">  <persistence-unit name="SimplePU" transaction-type="RESOURCE_LOCAL">  <provider>org.hibernate.ejb.HibernatePersistence</provider>  <class>footmark.springdata.jpa.domain.UserInfo</class>  <class>footmark.springdata.jpa.domain.AccountInfo</class>  <properties>  <property name="hibernate.connection.driver_class" value="com.MySQL.jdbc.Driver"/>  <property name="hibernate.connection.url"  value="jdbc:mysql://10.40.74.197:3306/zhangjp"/>  <property name="hibernate.connection.username" value="root"/>  <property name="hibernate.connection.password" value="root"/>  <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>  <property name="hibernate.show_sql" value="true"/>  <property name="hibernate.format_sql" value="true"/>  <property name="hibernate.use_sql_comments" value="false"/>  <property name="hibernate.hbm2ddl.auto" value="update"/>  </properties>  </persistence-unit>  </persistence>
清單 7. 本文使用如下的 main 方法進行開發者測試
 public class SimpleSpringJpaDemo {     public static void main(String[] args) {         new UserServiceImpl().createNewAccount("ZhangJianPing", "123456", 1);     }  }

簡述 Spring 框架對 JPA 的支持

接下來我們引入 Spring,以展示 Spring 框架對 JPA 的支持。業務層接口 UserService 保持不變,UserServiceImpl 中增加了三個注解,以讓 Spring 完成依賴注入,因此不再需要使用 new 操作符創建 UserDaoImpl 對象了。同時我們還使用了 Spring 的聲明式事務:

清單 8. 配置為 Spring Bean 的業務層實現
 @Service("userService")  public class UserServiceImpl implements UserService {  @Autowired  private UserDao userDao;  @Transactional  public AccountInfo createNewAccount(  String name, String pwd, Integer init) { …… }  }

對于持久層,UserDao 接口也不需要修改,只需修改 UserDaoImpl 實現,修改后的代碼如下:

清單 9. 配置為 Spring Bean 的持久層實現
 @Repository("userDao")  public class UserDaoImpl implements UserDao {  @PersistenceContext  private EntityManager em;  @Transactional    public Long save(AccountInfo accountInfo) {  em.persist(accountInfo);  return accountInfo.getAccountId();  }  }
清單 10. Spring 配置文件
 <?xml version="1.0" encoding="UTF-8"?>  <beans...>  <context:component-scan base-package="footmark.springdata.jpa"/>  <tx:annotation-driven transaction-manager="transactionManager"/>  <bean id="transactionManager"  class="org.springframework.orm.jpa.JpaTransactionManager">  <property name="entityManagerFactory" ref="entityManagerFactory"/>  </bean>  <bean id="entityManagerFactory" class= "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">     </bean>  </beans>
清單 11. 改造后的基于 Spring 的開發者測試代碼
 public class SimpleSpringJpaDemo{  public static void main(String[] args){  ClassPathXmlapplicationContext ctx =  new ClassPathXmlApplicationContext("spring-demo-cfg.xml");  UserDao userDao = ctx.getBean("userDao", UserDao.class);  userDao.createNewAccount("ZhangJianPing", "123456", 1);  }  }

通過對比重構前后的代碼,可以發現 Spring 對 JPA 的簡化已經非常出色了,我們可以大致總結一下 Spring 框架對 JPA 提供的支持主要體現在如下幾個方面:

首先,它使得 JPA 配置變得更加靈活。JPA 規范要求,配置文件必須命名為 persistence.xml,并存在于類路徑下的 META-INF 目錄中。該文件通常包含了初始化 JPA 引擎所需的全部信息。Spring 提供的 LocalContainerEntityManagerFactoryBean 提供了非常靈活的配置,persistence.xml 中的信息都可以在此以屬性注入的方式提供。其次,Spring 實現了部分在 EJB 容器環境下才具有的功能,比如對 @PersistenceContext、@PersistenceUnit 的容器注入支持。第三,也是最具意義的,Spring 將 EntityManager 的創建與銷毀、事務管理等代碼抽取出來,并由其統一管理,開發者不需要關心這些,如前面的代碼所示,業務方法中只剩下操作領域對象的代碼,事務管理和 EntityManager 創建、銷毀的代碼都不再需要開發者關心了。

更進一步:Spring Data JPA 讓一切近乎完美

通過前面的分析可以看出,Spring 對 JPA 的支持已經非常強大,開發者只需關心核心業務邏輯的實現代碼,無需過多關注 EntityManager 的創建、事務處理等 JPA 相關的處理,這基本上也是作為一個開發框架而言所能做到的極限了。然而,Spring 開發小組并沒有止步,他們再接再厲,于最近推出了 Spring Data JPA 框架,主要針對的就是 Spring 唯一沒有簡化到的業務邏輯代碼,至此,開發者連僅剩的實現持久層業務邏輯的工作都省了,唯一要做的,就只是聲明持久層的接口,其他都交給 Spring Data JPA 來幫你完成!

至此,讀者可能會存在一個疑問,框架怎么可能代替開發者實現業務邏輯呢?畢竟,每一個應用的持久層業務甚至領域對象都不盡相同,框架是怎么做到的呢?其實這背后的思想并不復雜,比如,當你看到 UserDao.findUserById() 這樣一個方法聲明,大致應該能判斷出這是根據給定條件的 ID 查詢出滿足條件的 User 對象。Spring Data JPA 做的便是規范方法的名字,根據符合規范的名字來確定方法需要實現什么樣的邏輯。

接下來我們針對前面的例子進行改造,讓 Spring Data JPA 來幫助我們完成業務邏輯。在著手寫代碼之前,開發者需要先 下載Spring Data JPA 的發布包(需要同時下載 Spring Data Commons 和 Spring Data JPA 兩個發布包,Commons 是 Spring Data 的公共基礎包),并把相關的依賴 JAR 文件加入到 CLASSPATH 中。

首先,讓持久層接口 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參考文檔。

應該繼承哪個接口?

前面提到,持久層接口繼承 Repository 并不是唯一選擇。Repository 接口是 Spring Data 的一個核心接口,它不提供任何方法,開發者需要在自己定義的接口中聲明需要的方法。與繼承 Repository 等價的一種方式,就是在持久層接口上使用 @RepositoryDefinition 注解,并為其指定 domainClass 和 idClass 屬性。如下兩種方式是完全等價的:

清單 15. 兩種等價的繼承接口方式示例
 public interface UserDao extends Repository<AccountInfo, Long> { …… }  @RepositoryDefinition(domainClass = AccountInfo.class, idClass = Long.class)  public interface UserDao { …… }

如果持久層接口較多,且每一個接口都需要聲明相似的增刪改查方法,直接繼承 Repository 就顯得有些啰嗦,這時可以繼承 CrudRepository,它會自動為域對象創建增刪改查方法,供業務層直接使用。開發者只是多寫了 "Crud" 四個字母,即刻便為域對象提供了開箱即用的十個增刪改查方法。

但是,使用 CrudRepository 也有副作用,它可能暴露了你不希望暴露給業務層的方法。比如某些接口你只希望提供增加的操作而不希望提供刪除的方法。針對這種情況,開發者只能退回到 Repository 接口,然后到 CrudRepository 中把希望保留的方法聲明復制到自定義的接口中即可。

分頁查詢和排序是持久層常用的功能,Spring Data 為此提供了 PagingAndSortingRepository 接口,它繼承自 CrudRepository 接口,在 CrudRepository 基礎上新增了兩個與分頁有關的方法。但是,我們很少會將自定義的持久層接口直接繼承自 PagingAndSortingRepository,而是在繼承 Repository 或 CrudRepository 的基礎上,在自己聲明的方法參數列表最后增加一個 Pageable 或 Sort 類型的參數,用于指定分頁或排序信息即可,這比直接使用 PagingAndSortingRepository 提供了更大的靈活性。

JpaRepository 是繼承自 PagingAndSortingRepository 的針對 JPA 技術提供的接口,它在父接口的基礎上,提供了其他一些方法,比如 flush(),saveAndFlush(),deleteInBatch() 等。如果有這樣的需求,則可以繼承該接口。

上述四個接口,開發者到底該如何選擇?其實依據很簡單,根據具體的業務需求,選擇其中之一。筆者建議在通常情況下優先選擇 Repository 接口。因為 Repository 接口已經能滿足日常需求,其他接口能做到的在 Repository 中也能做到,彼此之間并不存在功能強弱的問題。只是 Repository 需要顯示聲明需要的方法,而其他則可能已經提供了相關的方法,不需要再顯式聲明,但如果對 Spring Data JPA 不熟悉,別人在檢視代碼或者接手相關代碼時會有疑惑,他們不明白為什么明明在持久層接口中聲明了三個方法,而在業務層使用該接口時,卻發現有七八個方法可用,從這個角度而言,應該優先考慮使用 Repository 接口。

前面提到,Spring Data JPA 在后臺為持久層接口創建代理對象時,會解析方法名字,并實現相應的功能。除了通過方法名字以外,它還可以通過如下兩種方式指定查詢語句:

Spring Data JPA 可以訪問 JPA 命名查詢語句。開發者只需要在定義命名查詢語句時,為其指定一個符合給定格式的名字,Spring Data JPA 便會在創建代理對象時,使用該命名查詢語句來實現其功能。開發者還可以直接在聲明的方法上面使用 @Query 注解,并提供一個查詢語句作為參數,Spring Data JPA 在創建代理對象時,便以提供的查詢語句來實現其功能。

下面我們分別講述三種創建查詢的方式。

通過解析方法名創建查詢

通過前面的例子,讀者基本上對解析方法名創建查詢的方式有了一個大致的了解,這也是 Spring Data JPA 吸引開發者的一個很重要的因素。該功能其實并非 Spring Data JPA 首創,而是源自一個開源的 JPA 框架 Hades,該框架的作者 Oliver Gierke 本身又是 Spring Data JPA 項目的 Leader,所以把 Hades 的優勢引入到 Spring Data JPA 也就是順理成章的了。

框架在進行方法名解析時,會先把方法名多余的前綴截取掉,比如 find、findBy、read、readBy、get、getBy,然后對剩下部分進行解析。并且如果方法的最后一個參數是 Sort 或者 Pageable 類型,也會提取相關的信息,以便按規則進行排序或者分頁查詢。

在創建查詢時,我們通過在方法名中使用屬性名稱來表達,比如 findByUserAddressZip ()??蚣茉诮馕鲈摲椒〞r,首先剔除 findBy,然后對剩下的屬性進行解析,詳細規則如下(此處假設該方法針對的域對象為 AccountInfo 類型):

先判斷 userAddressZip (根據 POJO 規范,首字母變為小寫,下同)是否為 AccountInfo 的一個屬性,如果是,則表示根據該屬性進行查詢;如果沒有該屬性,繼續第二步;從右往左截取第一個大寫字母開頭的字符串(此處為 Zip),然后檢查剩下的字符串是否為 AccountInfo 的一個屬性,如果是,則表示根據該屬性進行查詢;如果沒有該屬性,則重復第二步,繼續從右往左截?。蛔詈蠹僭O user 為 AccountInfo 的一個屬性;接著處理剩下部分( AddressZip ),先判斷 user 所對應的類型是否有 addressZip 屬性,如果有,則表示該方法最終是根據 "AccountInfo.user.addressZip" 的取值進行查詢;否則繼續按照步驟 2 的規則從右往左截取,最終表示根據 "AccountInfo.user.address.zip" 的值進行查詢。

可能會存在一種特殊情況,比如 AccountInfo 包含一個 user 的屬性,也有一個 userAddress 屬性,此時會存在混淆。讀者可以明確在屬性之間加上 "_" 以顯式表達意圖,比如 "findByUser_AddressZip()" 或者 "findByUserAddress_Zip()"。

在查詢時,通常需要同時根據多個屬性進行查詢,且查詢的條件也格式各樣(大于某個值、在某個范圍等等),Spring Data JPA 為此提供了一些表達條件查詢的關鍵字,大致如下:

And --- 等價于 SQL 中的 and 關鍵字,比如 findByUsernameAndPassword(String user, Striang pwd);Or --- 等價于 SQL 中的 or 關鍵字,比如 findByUsernameOrAddress(String user, String addr);Between --- 等價于 SQL 中的 between 關鍵字,比如 findBySalaryBetween(int max, int min);LessThan --- 等價于 SQL 中的 "<",比如 findBySalaryLessThan(int max);GreaterThan --- 等價于 SQL 中的">",比如 findBySalaryGreaterThan(int min);IsNull --- 等價于 SQL 中的 "is null",比如 findByUsernameIsNull();IsNotNull --- 等價于 SQL 中的 "is not null",比如 findByUsernameIsNotNull();NotNull --- 與 IsNotNull 等價;Like --- 等價于 SQL 中的 "like",比如 findByUsernameLike(String user);NotLike --- 等價于 SQL 中的 "not like",比如 findByUsernameNotLike(String user);OrderBy --- 等價于 SQL 中的 "order by",比如 findByUsernameOrderBySalaryAsc(String user);Not --- 等價于 SQL 中的 "! =",比如 findByUsernameNot(String user);In --- 等價于 SQL 中的 "in",比如 findByUsernameIn(Collection<String> userList) ,方法的參數可以是 Collection 類型,也可以是數組或者不定長參數;NotIn --- 等價于 SQL 中的 "not in",比如 findByUsernameNotIn(Collection<String> userList) ,方法的參數可以是 Collection 類型,也可以是數組或者不定長參數;

使用 @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);

通過調用 JPA 命名查詢語句創建查詢

命名查詢是 JPA 提供的一種將查詢語句從方法體中獨立出來,以供多個方法共用的功能。Spring Data JPA 對命名查詢也提供了很好的支持。用戶只需要按照 JPA 規范在 orm.xml 文件或者在代碼中使用 @NamedQuery(或 @NamedNativeQuery)定義好查詢語句,唯一要做的就是為該語句命名時,需要滿足”DomainClass.methodName()”的命名規則。假設定義了如下接口:

清單 19. 使用 JPA 命名查詢時,聲明接口及方法時不需要什么特殊處理
 public interface UserDao extends Repository<AccountInfo, Long> {  ......     public List<AccountInfo> findTop5();  }

如果希望為 findTop5() 創建命名查詢,并與之關聯,我們只需要在適當的位置定義命名查詢語句,并將其命名為 "AccountInfo.findTop5",框架在創建代理類的過程中,解析到該方法時,優先查找名為 "AccountInfo.findTop5" 的命名查詢定義,如果沒有找到,則嘗試解析方法名,根據方法名字創建查詢。

創建查詢的順序

Spring Data JPA 在為接口創建代理對象時,如果發現同時存在多種上述情況可用,它該優先采用哪種策略呢?為此,<jpa:repositories> 提供了 query-lookup-strategy 屬性,用以指定查找的順序。它有如下三個取值:

create --- 通過解析方法名字來創建查詢。即使有符合的命名查詢,或者方法通過 @Query 指定的查詢語句,都將會被忽略。create-if-not-found --- 如果方法通過 @Query 指定了查詢語句,則使用該語句實現查詢;如果沒有,則查找是否定義了符合條件的命名查詢,如果找到,則使用該命名查詢;如果兩者都沒有找到,則通過解析方法名字來創建查詢。這是 query-lookup-strategy 屬性的默認值。use-declared-query --- 如果方法通過 @Query 指定了查詢語句,則使用該語句實現查詢;如果沒有,則查找是否定義了符合條件的命名查詢,如果找到,則使用該命名查詢;如果兩者都沒有找到,則拋出異常。

Spring Data JPA 對事務的支持

默認情況下,Spring Data JPA 實現的方法都是使用事務的。針對查詢類型的方法,其等價于 @Transactional(readOnly=true);增刪改類型的方法,等價于 @Transactional??梢钥闯觯藢⒉樵兊姆椒ㄔO為只讀事務外,其他事務屬性均采用默認值。

如果用戶覺得有必要,可以在接口方法上使用 @Transactional 顯式指定事務屬性,該值覆蓋 Spring Data JPA 提供的默認值。同時,開發者也可以在業務層方法上使用 @Transactional 指定事務屬性,這主要針對一個業務層方法多次調用持久層方法的情況。持久層的事務會根據設置的事務傳播行為來決定是掛起業務層事務還是加入業務層的事務。具體 @Transactional 的使用,請參考 Spring的參考文檔。

為接口中的部分方法提供自定義實現

有些時候,開發者可能需要在某些方法中做一些特殊的處理,此時自動生成的代理對象不能完全滿足要求。為了享受 Spring Data JPA 帶給我們的便利,同時又能夠為部分方法提供自定義實現,我們可以采用如下的方法:

將需要開發者手動實現的方法從持久層接口(假設為 AccountDao )中抽取出來,獨立成一個新的接口(假設為 AccountDaoPlus ),并讓 AccountDao 繼承 AccountDaoPlus;為 AccountDaoPlus 提供自定義實現(假設為 AccountDaoPlusImpl );將 AccountDaoPlusImpl 配置為 Spring Bean;在 <jpa:repositories> 中按清單 19 的方式進行配置。
清單 20. 指定自定義實現類
 <jpa:repositories base-package="footmark.springdata.jpa.dao">  <jpa:repository id="accountDao" repository-impl-ref=" accountDaoPlus " />  </jpa:repositories>  <bean id="accountDaoPlus" class="......."/>

此外,<jpa:repositories > 提供了一個 repository-impl-postfix 屬性,用以指定實現類的后綴。假設做了如下配置:

清單 21. 設置自動查找時默認的自定義實現類命名規則
 <jpa:repositories base-package="footmark.springdata.jpa.dao" repository-impl-postfix="Impl"/>

則在框架掃描到 AccountDao 接口時,它將嘗試在相同的包目錄下查找 AccountDaoImpl.java,如果找到,便將其中的實現方法作為最終生成的代理類中相應方法的實現。

結束語

本文主要介紹了 Spring Data JPA 的使用,以及它與 Spring 框架的無縫集成。Spring Data JPA 其實并不依賴于 Spring 框架,有興趣的讀者可以參考本文最后的"參考資源"進一步學習。

原文地址:https://www.ibm.com/developerworks/cn/opensource/os-cn-spring-jpa/


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲偷欧美偷国内偷| 在线观看日韩视频| 欧美二区乱c黑人| 久久综合九色九九| 欧美视频免费在线观看| 成人性生交xxxxx网站| 国产精品网红福利| 97国产精品免费视频| 国产日韩中文字幕在线| 日韩国产中文字幕| 久久久国产精品视频| 在线一区二区日韩| 精品激情国产视频| 久久精品久久久久| 日韩精品中文在线观看| 精品无人国产偷自产在线| 国产精品视频区| 国产精品都在这里| 亚洲精品美女在线观看| 亚洲第一级黄色片| 亚洲第一天堂av| 亚洲97在线观看| 亚洲国产精品人久久电影| 97香蕉久久夜色精品国产| 亚洲品质视频自拍网| 91视频国产高清| 亚洲国产精品久久| 4k岛国日韩精品**专区| 国产做受高潮69| 欧美精品videos| 国产精品看片资源| 国产精品久久久久久久久影视| 欧美一级淫片播放口| 国产精品伦子伦免费视频| 欧洲日韩成人av| 久久91亚洲人成电影网站| 性金发美女69hd大尺寸| 国产z一区二区三区| 亚洲一区二区福利| 亚洲欧美综合另类中字| 日韩视频免费中文字幕| 欧美超级乱淫片喷水| 亚洲摸下面视频| 97在线精品国自产拍中文| 国产精品免费视频久久久| 国产成人一区二区三区电影| 久久久国产精品免费| 亚洲国产精彩中文乱码av| 26uuu另类亚洲欧美日本一| 欧美日韩国产一区中文午夜| 亚洲视频欧洲视频| 亚洲自拍av在线| 亚洲视频欧洲视频| 精品女同一区二区三区在线播放| 亚洲色图狂野欧美| 91在线观看免费网站| 国产91ⅴ在线精品免费观看| 久久人人97超碰精品888| 精品视频www| 国产精品免费久久久久影院| 国产精品免费一区| 91久久久久久久久| 国产综合香蕉五月婷在线| 国产精品亚洲第一区| 成人黄色av免费在线观看| 亚洲国产天堂网精品网站| 亚洲专区国产精品| 日韩欧美主播在线| 久久天天躁狠狠躁夜夜躁2014| 精品欧美一区二区三区| 日韩av中文字幕在线播放| 日韩av成人在线观看| 日韩电影视频免费| 91精品啪aⅴ在线观看国产| 午夜精品在线视频| 日韩欧美高清在线视频| 欧美一级片免费在线| 欧美大胆在线视频| 日韩高清免费观看| 欧美精品在线观看| 成人av电影天堂| 欧美精品免费播放| 亚洲图片欧洲图片av| 一区二区三区四区在线观看视频| 88xx成人精品| 欧美高清视频免费观看| 成人在线观看视频网站| 欧美成aaa人片在线观看蜜臀| 亚洲成年人在线播放| 欧美人与性动交a欧美精品| 亚洲第一av网站| 国产精品户外野外| 久久99热精品这里久久精品| 久久亚洲国产精品成人av秋霞| 欧美成人亚洲成人日韩成人| 亚洲欧洲日产国码av系列天堂| 欧美午夜精品久久久久久久| 国产ts人妖一区二区三区| 国语自产精品视频在线看一大j8| 国产精品视频区1| 亚洲影院色无极综合| 日韩美女免费视频| 中文字幕日韩在线视频| 国语自产精品视频在免费| 中文字幕亚洲一区二区三区五十路| 成人激情视频网| 欧美在线视频免费| 91精品综合视频| 欧美日韩成人精品| 亚洲欧美中文字幕| 久操成人在线视频| 久久久久久久久国产| 韩国19禁主播vip福利视频| 国内精品久久久久影院优| 亚洲3p在线观看| 国产精品自产拍在线观看| 91国产视频在线| 在线观看欧美日韩国产| 日韩av一区在线观看| 一本一本久久a久久精品综合小说| 亚洲免费成人av电影| 国语自产精品视频在线看一大j8| 亚洲人成77777在线观看网| 久久久久久com| 精品美女国产在线| 国产精品99久久久久久www| 97在线看免费观看视频在线观看| 成人精品久久一区二区三区| 日韩av免费网站| 久久久久久久影视| 亚洲一区中文字幕在线观看| 欧美在线精品免播放器视频| 97高清免费视频| 国产免费一区二区三区香蕉精| 亚洲美女在线看| 91在线免费网站| 欧美国产一区二区三区| 亚洲成人在线视频播放| 亚洲欧洲午夜一线一品| 久久成年人视频| 欧美另类精品xxxx孕妇| 中文字幕不卡av| 欧美日韩国产影院| 在线免费观看羞羞视频一区二区| 欧美成人精品一区二区三区| 国产精品久久久久久久午夜| 欧美激情亚洲精品| 国外成人免费在线播放| 国产精品一久久香蕉国产线看观看| 国产成人亚洲精品| 国产午夜精品全部视频在线播放| 日韩欧美国产网站| 热re91久久精品国99热蜜臀| 欧美日韩在线一区| 青青久久av北条麻妃海外网| 亚洲国产天堂久久综合网| 国产有码在线一区二区视频| 亚洲欧美制服第一页| 777国产偷窥盗摄精品视频| 91中文字幕在线| 日本免费在线精品| 国产激情久久久久| 日韩中文字幕在线| 日日狠狠久久偷偷四色综合免费|