javascript
Spring Data JPA 从入门到精通~自定义实现Repository
EntityManager 的獲取方式
我們既然要自定義,首先講一下 EntityManager 的兩種獲取方式。
1. 通過(guò) @PersistenceContext 注解。
通過(guò)將 @PersistenceContext 注解標(biāo)注在 EntityManager 類(lèi)型的字段上,這樣得到的 EntityManager 就是容器管理的 EntityManager。由于是容器管理的,所以我們不需要也不應(yīng)該顯式關(guān)閉注入的 EntityManager 實(shí)例。
@Repository @Transactional(readOnly = true) public class UserRepositoryImpl implements UserRepositoryCustom {@PersistenceContext //獲得entityManager的實(shí)例EntityManager entityManager; }2. 繼承 SimpleJpaRepository 成為子類(lèi),實(shí)現(xiàn)構(gòu)造方法即可,這時(shí)候我們直接用父類(lèi)里面的 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 的兩種場(chǎng)景
我們自定義實(shí)現(xiàn) Repository,主要的應(yīng)用場(chǎng)景有兩種:
- 個(gè)別特殊化場(chǎng)景,私有的。
- 公用的通用的場(chǎng)景,替代默認(rèn)的 SimpleJpaRepository 的場(chǎng)景,架構(gòu)層面出發(fā)。
1. 自定義個(gè)別的特殊場(chǎng)景,私有的 Repository。
這種方法就是需要自己創(chuàng)建一個(gè)接口,和對(duì)應(yīng)的接口實(shí)現(xiàn)類(lèi),若需要用到特殊化的實(shí)現(xiàn)方法的話,***Respository 只需要繼承你自定義的接口即可,主要有兩種能力:
- 實(shí)現(xiàn)自定義接口
- 可以直接覆蓋 Spring Data JPA 給我們提供的默認(rèn) ***Respository 的接口里面的方法。
案例1:單個(gè)私有的 Repository 接口實(shí)現(xiàn)類(lèi)
(1)創(chuàng)建自定義接口
/*** @author jack*/ public interface UserRepositoryCustom {/*** 自定義一個(gè)查詢方法,name的like查詢,此處僅僅是演示例子,實(shí)際中直接用QueryMethod即可* @param firstName* @return*/List<User> customerMethodNamesLike(String firstName); }(2)自定義存儲(chǔ)庫(kù)功能的實(shí)現(xiàn)
/*** 用@Repository 將此實(shí)現(xiàn)交個(gè)Spring bean加載* 咱們模仿SimpleJpaRepository 默認(rèn)將所有方法都開(kāi)啟一個(gè)事務(wù)*/ @Repository @Transactional(readOnly = true) public class UserRepositoryCustomImpl implements UserRepositoryCustom {@PersistenceContextEntityManager entityManager;/*** 自定義一個(gè)查詢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,當(dāng)然了也不排除自己通過(guò)最底層的 JdbcTemplate 來(lái)自己實(shí)現(xiàn)邏輯。
(3)由于這個(gè)接口是為 User 單獨(dú)寫(xiě)的,但是同時(shí)也可以繼承和 @Repository 的任何子類(lèi)。
/*** 使用的時(shí)候直接繼承 UserRepositoryCustom接口即可*/ public interface UserRepository extends Repository<User, Long>,UserRepositoryCustom { }Controller 的調(diào)用方式如下:
/*** 調(diào)用我們自定義的實(shí)現(xiàn)方法** @return*/ @GetMapping(path = "/customer") @ResponseBody public Iterable<User> findCustomerMethodNamesLike() {return userRepository.customerMethodNamesLike("jack"); }(4)其實(shí)通過(guò)上述方法我們可以實(shí)現(xiàn)多個(gè)自定義接口:
//如:我們自定義了HumanCustomerRepository, ContactCustomerRepository兩個(gè)Repository interface UserRepository extends CrudRepository<User, Long>, HumanCustomerRepository, ContactCustomerRepository {// 用的時(shí)候只需要繼承多個(gè)自定義接口即可 }(5)覆蓋 JPA 里面的默認(rèn)實(shí)現(xiàn)方法
Spring Data JPA 的底層實(shí)現(xiàn)里面,自定義的 Repositories 的實(shí)現(xiàn)類(lèi)和方法要高于它幫我們提供的 Repositories,所以當(dāng)我們有場(chǎng)景需要覆蓋默認(rèn)實(shí)現(xiàn)的時(shí)候其 demo 如下:
//假設(shè)我們要覆蓋默認(rèn)的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通過(guò)泛化可以被多個(gè)Repository使用 interface PersonRepository extends CrudRepository<Person, Long>, CustomizedSave<Person> { }實(shí)際工作中應(yīng)用于邏輯刪除場(chǎng)景:
在實(shí)際工作的生產(chǎn)環(huán)境中,我們可能經(jīng)常會(huì)用到邏輯刪除,所以做法是一般自定義覆蓋 Data JPA 幫我們提供 remove 方法,然后實(shí)現(xiàn)邏輯刪除的邏輯即可。
2:公用的通用的場(chǎng)景,替代默認(rèn)的 SimpleJpaRepository 的場(chǎng)景,從架構(gòu)層面出發(fā)。
案例2:定義一個(gè)公用的 Repository 接口的實(shí)現(xiàn)類(lèi)。
通過(guò)構(gòu)造方法獲得 EntityManager,需要用到 Java 的泛化技術(shù)。當(dāng)你想將一個(gè)方法添加到所有的存儲(chǔ)庫(kù)接口時(shí),上述方法是不可行的,要將自定義行為添加到所有存儲(chǔ)庫(kù),首先添加一個(gè)中間接口來(lái)聲明共享行為。
(1)聲明定制共享行為的接口,用 @NoRepositoryBean:
//因?yàn)橐?#xff0c;所以必須要通用,不能失去本身的Spring Data JPA給我們提供的默認(rèn)方法,所有我們繼承相關(guān)的Repository類(lèi) @NoRepositoryBean public interface MyRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {void sharedCustomMethod(ID id); }(2)繼承 SimpleJpaRepository 擴(kuò)展自己的方法實(shí)現(xiàn)邏輯:
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) {// 通過(guò)entityManager實(shí)現(xiàn)自己的額外方法的實(shí)現(xiàn)邏輯。這里不多說(shuō)了} }注意:該類(lèi)需要具有專(zhuān)門(mén)的存儲(chǔ)庫(kù)工廠實(shí)現(xiàn)使用超級(jí)類(lèi)的構(gòu)造函數(shù),如果存儲(chǔ)庫(kù)基類(lèi)有多個(gè)構(gòu)造函數(shù),則覆蓋一個(gè) EntityInformation 加上特定于存儲(chǔ)的基礎(chǔ)架構(gòu)對(duì)象(例如,一個(gè) EntityManager 或一個(gè)模板類(lèi)),也可以重寫(xiě) SimpleJpaRepository 的任何邏輯。如邏輯刪除放在這里面實(shí)現(xiàn),就不要所有的 Repository 去關(guān)心實(shí)現(xiàn)哪個(gè)接口了。
(3)使用 JavaConfig 配置自定義 MyRepositoryImpl 作為其他接口的動(dòng)態(tài)代理的實(shí)現(xiàn)基類(lèi)。
具有全局的性質(zhì),即使沒(méi)有繼承它所有的動(dòng)態(tài)代理類(lèi)也會(huì)變成它。
@Configuration @EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class) class ApplicationConfiguration { … }(4)使用的時(shí)候就可以顯示的選擇用哪個(gè)接口,從而選擇性的暴露 SimpleJpaRepository 的實(shí)現(xiàn)方法。
現(xiàn)在,各個(gè)存儲(chǔ)庫(kù)接口將擴(kuò)展此中間接口,而不是擴(kuò)展 Repository 接口以包含聲明的功能。接下來(lái),創(chuàng)建擴(kuò)展了持久性技術(shù)特定的存儲(chǔ)庫(kù)基類(lèi)的中間接口的實(shí)現(xiàn)。然后,該類(lèi)將用作存儲(chǔ)庫(kù)代理的自定義基類(lèi)。
//如果你要使用你自定義的全局MyRepositoryImpl只需要繼承接口即可,如下: interface PersonRepository extends MyRepositoryImpl<Person, Long>{ }總結(jié)
以上是生活随笔為你收集整理的Spring Data JPA 从入门到精通~自定义实现Repository的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java技术回顾之JNDI--实例
- 下一篇: gradle idea java ssm