javascript
Spring Data JPA 从入门到精通~自定义实现Repository
EntityManager 的獲取方式
我們既然要自定義,首先講一下 EntityManager 的兩種獲取方式。
1. 通過 @PersistenceContext 注解。
通過將 @PersistenceContext 注解標注在 EntityManager 類型的字段上,這樣得到的 EntityManager 就是容器管理的 EntityManager。由于是容器管理的,所以我們不需要也不應該顯式關閉注入的 EntityManager 實例。
@Repository @Transactional(readOnly = true) public class UserRepositoryImpl implements UserRepositoryCustom {@PersistenceContext //獲得entityManager的實例EntityManager entityManager; }2. 繼承 SimpleJpaRepository 成為子類,實現構造方法即可,這時候我們直接用父類里面的 EntityManager 即可。
public class BaseRepositoryCustom<T, ID> extends SimpleJpaRepository<T, ID> {public BaseRepositoryCustom(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {super(entityInformation, entityManager);}public BaseRepositoryCustom(Class<T> domainClass, EntityManager em) {super(domainClass, em);} }自定義 Repository 的兩種場景
我們自定義實現 Repository,主要的應用場景有兩種:
- 個別特殊化場景,私有的。
- 公用的通用的場景,替代默認的 SimpleJpaRepository 的場景,架構層面出發。
1. 自定義個別的特殊場景,私有的 Repository。
這種方法就是需要自己創建一個接口,和對應的接口實現類,若需要用到特殊化的實現方法的話,***Respository 只需要繼承你自定義的接口即可,主要有兩種能力:
- 實現自定義接口
- 可以直接覆蓋 Spring Data JPA 給我們提供的默認 ***Respository 的接口里面的方法。
案例1:單個私有的 Repository 接口實現類
(1)創建自定義接口
/*** @author jack*/ public interface UserRepositoryCustom {/*** 自定義一個查詢方法,name的like查詢,此處僅僅是演示例子,實際中直接用QueryMethod即可* @param firstName* @return*/List<User> customerMethodNamesLike(String firstName); }(2)自定義存儲庫功能的實現
/*** 用@Repository 將此實現交個Spring bean加載* 咱們模仿SimpleJpaRepository 默認將所有方法都開啟一個事務*/ @Repository @Transactional(readOnly = true) public class UserRepositoryCustomImpl implements UserRepositoryCustom {@PersistenceContextEntityManager entityManager;/*** 自定義一個查詢firstname的方法* @param firstName* @return*/@Overridepublic List<User> customerMethodNamesLike(String firstName) {Query query = entityManager.createNativeQuery("SELECT u.* FROM user as u " +"WHERE u.name LIKE ?", User.class);query.setParameter(1, firstName + "%");return query.getResultList();} }我們這里采用 entityManager,當然了也不排除自己通過最底層的 JdbcTemplate 來自己實現邏輯。
(3)由于這個接口是為 User 單獨寫的,但是同時也可以繼承和 @Repository 的任何子類。
/*** 使用的時候直接繼承 UserRepositoryCustom接口即可*/ public interface UserRepository extends Repository<User, Long>,UserRepositoryCustom { }Controller 的調用方式如下:
/*** 調用我們自定義的實現方法** @return*/ @GetMapping(path = "/customer") @ResponseBody public Iterable<User> findCustomerMethodNamesLike() {return userRepository.customerMethodNamesLike("jack"); }(4)其實通過上述方法我們可以實現多個自定義接口:
//如:我們自定義了HumanCustomerRepository, ContactCustomerRepository兩個Repository interface UserRepository extends CrudRepository<User, Long>, HumanCustomerRepository, ContactCustomerRepository {// 用的時候只需要繼承多個自定義接口即可 }(5)覆蓋 JPA 里面的默認實現方法
Spring Data JPA 的底層實現里面,自定義的 Repositories 的實現類和方法要高于它幫我們提供的 Repositories,所以當我們有場景需要覆蓋默認實現的時候其 demo 如下:
//假設我們要覆蓋默認的save方法的邏輯 interface CustomizedSave<T> {<S extends T> S save(S entity); } class CustomizedSaveImpl<T> implements CustomizedSave<T> {public <S extends T> S save(S entity) {// Your custom implementation} } //用法保持不變,如下: interface UserRepository extends CrudRepository<User, Long>, CustomizedSave<User> { } //CustomizedSave通過泛化可以被多個Repository使用 interface PersonRepository extends CrudRepository<Person, Long>, CustomizedSave<Person> { }實際工作中應用于邏輯刪除場景:
在實際工作的生產環境中,我們可能經常會用到邏輯刪除,所以做法是一般自定義覆蓋 Data JPA 幫我們提供 remove 方法,然后實現邏輯刪除的邏輯即可。
2:公用的通用的場景,替代默認的 SimpleJpaRepository 的場景,從架構層面出發。
案例2:定義一個公用的 Repository 接口的實現類。
通過構造方法獲得 EntityManager,需要用到 Java 的泛化技術。當你想將一個方法添加到所有的存儲庫接口時,上述方法是不可行的,要將自定義行為添加到所有存儲庫,首先添加一個中間接口來聲明共享行為。
(1)聲明定制共享行為的接口,用 @NoRepositoryBean:
//因為要公用,所以必須要通用,不能失去本身的Spring Data JPA給我們提供的默認方法,所有我們繼承相關的Repository類 @NoRepositoryBean public interface MyRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {void sharedCustomMethod(ID id); }(2)繼承 SimpleJpaRepository 擴展自己的方法實現邏輯:
public class MyRepositoryImpl<T, ID extends Serializable>extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {private final EntityManager entityManager;public MyRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) {super(entityInformation, entityManager);// Keep the EntityManager around to used from the newly introduced methods.this.entityManager = entityManager;}public void sharedCustomMethod(ID id) {// 通過entityManager實現自己的額外方法的實現邏輯。這里不多說了} }注意:該類需要具有專門的存儲庫工廠實現使用超級類的構造函數,如果存儲庫基類有多個構造函數,則覆蓋一個 EntityInformation 加上特定于存儲的基礎架構對象(例如,一個 EntityManager 或一個模板類),也可以重寫 SimpleJpaRepository 的任何邏輯。如邏輯刪除放在這里面實現,就不要所有的 Repository 去關心實現哪個接口了。
(3)使用 JavaConfig 配置自定義 MyRepositoryImpl 作為其他接口的動態代理的實現基類。
具有全局的性質,即使沒有繼承它所有的動態代理類也會變成它。
@Configuration @EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class) class ApplicationConfiguration { … }(4)使用的時候就可以顯示的選擇用哪個接口,從而選擇性的暴露 SimpleJpaRepository 的實現方法。
現在,各個存儲庫接口將擴展此中間接口,而不是擴展 Repository 接口以包含聲明的功能。接下來,創建擴展了持久性技術特定的存儲庫基類的中間接口的實現。然后,該類將用作存儲庫代理的自定義基類。
//如果你要使用你自定義的全局MyRepositoryImpl只需要繼承接口即可,如下: interface PersonRepository extends MyRepositoryImpl<Person, Long>{ }總結
以上是生活随笔為你收集整理的Spring Data JPA 从入门到精通~自定义实现Repository的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java技术回顾之JNDI--实例
- 下一篇: 有效的单元测试--总结