欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JpaRepository如何實(shí)現(xiàn)增刪改查并進(jìn)行單元測(cè)試

 更新時(shí)間:2021年11月25日 09:58:47   作者:yeungsinsin  
這篇文章主要介紹了JpaRepository如何實(shí)現(xiàn)增刪改查并進(jìn)行單元測(cè)試,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

JpaRepository增刪改查進(jìn)行單元測(cè)試

項(xiàng)目結(jié)構(gòu)

在這里插入圖片描述

創(chuàng)建UserInfoDaoI.java文件,繼承JpaRepository。(不需要實(shí)現(xiàn)類)

在這里插入圖片描述

根據(jù)條件查詢/刪除

在這里插入圖片描述

更新

在這里插入圖片描述

參考此文章進(jìn)行開發(fā)

單元測(cè)試

在這里插入圖片描述

SpringDataJPA的Repository理解

repository抽取擴(kuò)展理解

在SpringDataJPA中使用repository來進(jìn)行數(shù)據(jù)層操作(作用相當(dāng)于dao層),直接使用repository對(duì)象調(diào)用已經(jīng)實(shí)現(xiàn)好的數(shù)據(jù)層操作方法進(jìn)行CRUD、分頁、排序等操作,還可以在自定義repository接口中依據(jù)一定規(guī)則擴(kuò)展功能。在一個(gè)項(xiàng)目中,我們平常需要為每一個(gè)實(shí)體類都創(chuàng)建一個(gè)repository接口,我們自定義的repository接口都需要去繼承JpaRepository接口,以具有所有的數(shù)據(jù)層操作功能,但也僅僅限于簡(jiǎn)單查詢等操作。通常我們?yōu)榱四軐?shí)現(xiàn)復(fù)雜查詢操作,會(huì)繼續(xù)繼承JpaSpecificationExecutor接口,簡(jiǎn)單說就是建立一個(gè)規(guī)則來進(jìn)行查詢。

這樣雖然在很大程度上簡(jiǎn)化了開發(fā)代碼難度,但在為每一實(shí)體類創(chuàng)建對(duì)應(yīng)repository接口時(shí),發(fā)現(xiàn)存在大量的重復(fù)代碼,這時(shí)很容易的我們會(huì)想到抽取父類來簡(jiǎn)化一些公共代碼并順帶可以對(duì)子類進(jìn)行一些規(guī)范。雖然SpringDataJPA提供的功能已經(jīng)足夠強(qiáng)大了,但是依然還是不能滿足實(shí)際開發(fā)中的所有需求,所以我們想在抽取父類的同時(shí)實(shí)現(xiàn)對(duì)其功能的擴(kuò)展。在進(jìn)行這個(gè)操作之前我們需要了解一下整個(gè)repository的結(jié)構(gòu)。

應(yīng)該免不了有疑問,我們僅僅是定義了一個(gè)接口去實(shí)現(xiàn)了JpaRepository接口,怎么就能創(chuàng)建對(duì)象了,而且還能給我們實(shí)現(xiàn)一系列的數(shù)據(jù)層操作?這就要從為什么自定義repository接口要去繼承JpaRepository接口說起了:

在這里插入圖片描述

通過它的結(jié)構(gòu)圖可以看出,JpaRepository的父類分別是PagingAndSortingRepository、CrudRepository和Repository,前兩個(gè)接口中前者定義了分頁和排序功能,后者看名字就可以知道里面全是CRUD操作,值得注意的是,它這保存和修改方法都是save。Repository接口呢沒有定義任何功能,它的作用就是標(biāo)識(shí)。這么說吧我們自定義的接口繼承JpaRepository接口就相當(dāng)于繼承了Repository接口,那么SpringDataJPA在掃描時(shí)只要掃描到我們某個(gè)接口實(shí)現(xiàn)了Repository接口,就為自動(dòng)的為其創(chuàng)建代理實(shí)現(xiàn)子類(通過AOP實(shí)現(xiàn))。但是為什么就只為我們自定義的repository接口創(chuàng)建了實(shí)現(xiàn)子類而沒有為PagingAndSortingRepository、CrudRepository、JpaRepository創(chuàng)建呢?這個(gè)同樣能從結(jié)構(gòu)圖中看出答案:它們都是打上了NoRepositoryBean注解的,凡是打上了這個(gè)注解的接口SPringDataJPA都不會(huì)為其創(chuàng)建實(shí)現(xiàn)子類。

這樣一來,我們自定義的接口繼承了以上三個(gè)接口后就相當(dāng)于“集百家之長(zhǎng)”了,擁有了它們所有功能,但是問題又來了,它們?cè)倥=K歸還是接口啊,又不能創(chuàng)建對(duì)象,是怎么操作的呢?

在這里插入圖片描述

原來,SpringDataJPA自動(dòng)的為自動(dòng)創(chuàng)建的repository實(shí)現(xiàn)子類繼承了SimpleJpaRepository類,而SimpleJpaRepository又是SpringDataJPA的Repository默認(rèn)實(shí)現(xiàn)兩大方式之一,自然而然的自動(dòng)創(chuàng)建的repository代理子類也就具有了所有的功能。至此,SpringDataJPA中repository實(shí)現(xiàn)數(shù)據(jù)層操作的原理也大概講清楚了,接下來就說說擴(kuò)展了:雖然SPringDataJPA提供的功能已經(jīng)足夠強(qiáng)大了,但是依然還是不能滿足實(shí)際開發(fā)中的所有需求。所以說了這么久終于要說到重點(diǎn)了:抽取父類、擴(kuò)展功能。

在這里插入圖片描述

通過上圖,大概也能看出結(jié)構(gòu)了,大概思想:在原本應(yīng)該繼承JpaRepository的實(shí)體類repository接口與JpaRepository之間增加了一層而已,讓BaseRepository繼承JpaSpecificationExecutor、JpaRepository,實(shí)體類repository接口繼承BaseRepository接口;這樣便能實(shí)現(xiàn)在擁有原有SpringDataJPA的Repository功能的情況下在BaseRepository擴(kuò)展其他功能,但在這需要注意:在SpringDataJPA中默認(rèn)會(huì)使自動(dòng)創(chuàng)建的repository代理實(shí)現(xiàn)子類(例:圖中的EmployeeRepositoryImpl)去繼承SimpleJpaRepository,很明顯我們并不能使用默認(rèn)的,因?yàn)檫@樣會(huì)使得我們的BaseRepository接口定義的一無是處,所以我們需要再創(chuàng)建一個(gè)自定義的BaseRepository實(shí)現(xiàn)BaseRepositoryImpl繼承SimpleJpaRepository,再修改配置使得SpringDataJPA自動(dòng)創(chuàng)建出的所有實(shí)體類repository的實(shí)現(xiàn)代理子類都去繼承我們的BaseRepositoryImpl,這樣我們便能徹底實(shí)現(xiàn)擴(kuò)展了。

前面說過SpringDataJPA會(huì)默認(rèn)的將自動(dòng)創(chuàng)建出的實(shí)現(xiàn)代理子類繼承SimpleJpaRepository類,所以我們需要修改SimpleJpaRepository為我們自定義的BaseRepositoryImpl類,SpringDataJPA是通過JpaRepositoryFactoryBean來實(shí)現(xiàn)創(chuàng)建并繼承過程的。我們只用自定義一個(gè)BaseRepositoryFactoryBean來繼承JpaRepositoryFactoryBean,接下來只用修改最終返回功能對(duì)象,和確定功能對(duì)象的類型即可。最后記得要在spring的配置文件中在SpringDataJPA的配置中添加修改創(chuàng)建對(duì)象的factoryBean為我們自定義的BaseRepositoryFactoryBean。

最后,記得修改各實(shí)體repository接口繼承我們定義的BaseRepository接口

接下來貼一貼代碼

接下來貼一貼代碼

BaseRepository

import com.xer.aisell.query.BaseQuery;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
import java.io.Serializable;
import java.util.List;
/**
 * 雖然jpadata提供的功能已經(jīng)足夠強(qiáng)大了,但是依然還是不能滿足實(shí)際開發(fā)中的所有需求
 * 所以希望在具有它功能的前提下再拓展一些功能
 * 之前是通過每個(gè)實(shí)體類的repository接口來直接繼承JpaRepository接口,現(xiàn)在我們可以在中間添加一個(gè)父類接口BaseRepository
 * BaseRepository繼承JpaRepository,再由實(shí)體類repository來繼承BaseRepository
 * 這樣就能夠?qū)崿F(xiàn)既實(shí)現(xiàn)了功能,又能隨時(shí)擴(kuò)展功能
 * @param <T>
 * @param <ID>
 */
@NoRepositoryBean
public interface BaseRepository<T,ID extends Serializable> extends JpaRepository<T,ID>,JpaSpecificationExecutor<T>{
    //根據(jù)Query拿到分頁對(duì)象(分頁)
    Page findPageByQuery(BaseQuery baseQuery);
    //根據(jù)Query拿到對(duì)應(yīng)的所有數(shù)據(jù)(不分頁)
    List<T> findByQuery(BaseQuery baseQuery);
    //根據(jù)jpql與對(duì)應(yīng)的參數(shù)拿到數(shù)據(jù)
    List findByJpql(String jpql,Object... values);
}

BaseRepositoryImpl

import com.xer.aisell.query.BaseQuery;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.io.Serializable;
import java.util.List;
public class BaseRepositoryImpl<T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements BaseRepository<T,ID> {
    private final EntityManager entityManager;
    public BaseRepositoryImpl(Class<T> domainClass, EntityManager em) {
        super(domainClass, em);
        this.entityManager = em;
    }
    @Override
    /**
     * 分頁
     */
    public Page findPageByQuery(BaseQuery baseQuery) {
        //拿到條件
        Specification spec = baseQuery.createSpec();
        //創(chuàng)建排序
        Sort sort = baseQuery.getSort();
        //分頁
        Pageable page = new PageRequest(baseQuery.getJPACurrentPage(), baseQuery.getPageSize(), sort);
        return super.findAll(spec,page);
    }
    /**
     * 不分頁查詢
     * @param baseQuery
     * @return
     */
    @Override
    public List findByQuery(BaseQuery baseQuery) {
        //獲取到條件
        Specification spec = baseQuery.createSpec();
        //排序
        Sort sort = baseQuery.getSort();
        return super.findAll(spec,sort);
    }
    /**
     *
     * 根據(jù)傳入JPQL查詢
     * @param jpql
     * @param values
     * @return
     */
    @Override
    public List findByJpql(String jpql, Object... values) {
        Query query = entityManager.createQuery(jpql);
        //為傳入JPQL填充條件值
        if (values != null) {
            for (int i = 0;i < values.length;i++) {
                query.setParameter(i+1,values[i]);
            }
        }
        return query.getResultList();
    }
}

EmployeeRepository接口

import com.xer.aisell.domain.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
/***
 *用于數(shù)據(jù)庫操作
 */
public interface EmployeeRepository extends BaseRepository<Employee,Long> {
    /**
     * 可以自己擴(kuò)展
     */
    List<Employee> findByUsernameLike(String username);
    /**
     * 使用@Query
     *  實(shí)現(xiàn)自己寫JPQL查詢
     */
    @Query("select o from Employee o where username like ?1")
    List<Employee> findByUsername(String username);
    /**
     * 當(dāng)然也可以實(shí)現(xiàn)自己寫SQL
     */
    @Query(nativeQuery = true,value = "SELECT COUNT(*) FROM employee")
    Long getCount();
}

BaseRepositoryFactoryBean類(難)

import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import javax.persistence.EntityManager;
import java.io.Serializable;
public class BaseRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T,S,ID> {
    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
        return new MyRepositoryFactory<T,ID>(entityManager); //注:這里創(chuàng)建是我們的自定義類
    }
    //繼承JpaRepositoryFactory后,把返回的對(duì)象修改成我們自己的實(shí)現(xiàn)
    private static  class MyRepositoryFactory<T,ID extends Serializable>   extends JpaRepositoryFactory {
        private final EntityManager entityManager;
        /**
         * Creates a new {@link JpaRepositoryFactory}.
         *
         * @param entityManager must not be {@literal null}
         */
        public MyRepositoryFactory(EntityManager entityManager) {
            super(entityManager);
            this.entityManager = entityManager;
        }
        //這里返回最后的功能對(duì)象
        @Override
        protected Object getTargetRepository(RepositoryInformation information) {
            return new BaseRepositoryImpl<T,ID>((Class<T>)information.getDomainType(),entityManager);
        }
        //確定功能對(duì)象的類型
        @Override
        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
            return BaseRepositoryImpl.class;
        }
    }
}

spring配置文件中關(guān)于SpringDataJPA的配置

 <jpa:repositories base-package="com.xer.aisell.dao" entity-manager-factory-ref="entityManagerFactory"
                      transaction-manager-ref="transactionManager"
                        factory-class="com.xer.aisell.dao.BaseRepositoryFactoryBean"/>

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論