JpaRepository如何实现增删改查并进行单元测试

目录
  • JpaRepository增删改查进行单元测试
    • 项目结构
    • 单元测试
  • SpringDataJPA的Repository理解
    • repository抽取扩展理解
    • 接下来贴一贴代码

JpaRepository增删改查进行单元测试

项目结构

创建UserInfoDaoI.java文件,继承JpaRepository。(不需要实现类)

根据条件查询/删除

更新

参考此文章进行开发

单元测试

SpringDataJPA的Repository理解

repository抽取扩展理解

在SpringDataJPA中使用repository来进行数据层操作(作用相当于dao层),直接使用repository对象调用已经实现好的数据层操作方法进行CRUD、分页、排序等操作,还可以在自定义repository接口中依据一定规则扩展功能。在一个项目中,我们平常需要为每一个实体类都创建一个repository接口,我们自定义的repository接口都需要去继承JpaRepository接口,以具有所有的数据层操作功能,但也仅仅限于简单查询等操作。通常我们为了能实现复杂查询操作,会继续继承JpaSpecificationExecutor接口,简单说就是建立一个规则来进行查询。

这样虽然在很大程度上简化了开发代码难度,但在为每一实体类创建对应repository接口时,发现存在大量的重复代码,这时很容易的我们会想到抽取父类来简化一些公共代码并顺带可以对子类进行一些规范。虽然SpringDataJPA提供的功能已经足够强大了,但是依然还是不能满足实际开发中的所有需求,所以我们想在抽取父类的同时实现对其功能的扩展。在进行这个操作之前我们需要了解一下整个repository的结构。

应该免不了有疑问,我们仅仅是定义了一个接口去实现了JpaRepository接口,怎么就能创建对象了,而且还能给我们实现一系列的数据层操作?这就要从为什么自定义repository接口要去继承JpaRepository接口说起了:

通过它的结构图可以看出,JpaRepository的父类分别是PagingAndSortingRepository、CrudRepository和Repository,前两个接口中前者定义了分页和排序功能,后者看名字就可以知道里面全是CRUD操作,值得注意的是,它这保存和修改方法都是save。Repository接口呢没有定义任何功能,它的作用就是标识。这么说吧我们自定义的接口继承JpaRepository接口就相当于继承了Repository接口,那么SpringDataJPA在扫描时只要扫描到我们某个接口实现了Repository接口,就为自动的为其创建代理实现子类(通过AOP实现)。但是为什么就只为我们自定义的repository接口创建了实现子类而没有为PagingAndSortingRepository、CrudRepository、JpaRepository创建呢?这个同样能从结构图中看出答案:它们都是打上了NoRepositoryBean注解的,凡是打上了这个注解的接口SPringDataJPA都不会为其创建实现子类。

这样一来,我们自定义的接口继承了以上三个接口后就相当于“集百家之长”了,拥有了它们所有功能,但是问题又来了,它们再牛终归还是接口啊,又不能创建对象,是怎么操作的呢?

原来,SpringDataJPA自动的为自动创建的repository实现子类继承了SimpleJpaRepository类,而SimpleJpaRepository又是SpringDataJPA的Repository默认实现两大方式之一,自然而然的自动创建的repository代理子类也就具有了所有的功能。至此,SpringDataJPA中repository实现数据层操作的原理也大概讲清楚了,接下来就说说扩展了:虽然SPringDataJPA提供的功能已经足够强大了,但是依然还是不能满足实际开发中的所有需求。所以说了这么久终于要说到重点了:抽取父类、扩展功能。

通过上图,大概也能看出结构了,大概思想:在原本应该继承JpaRepository的实体类repository接口与JpaRepository之间增加了一层而已,让BaseRepository继承JpaSpecificationExecutor、JpaRepository,实体类repository接口继承BaseRepository接口;这样便能实现在拥有原有SpringDataJPA的Repository功能的情况下在BaseRepository扩展其他功能,但在这需要注意:在SpringDataJPA中默认会使自动创建的repository代理实现子类(例:图中的EmployeeRepositoryImpl)去继承SimpleJpaRepository,很明显我们并不能使用默认的,因为这样会使得我们的BaseRepository接口定义的一无是处,所以我们需要再创建一个自定义的BaseRepository实现BaseRepositoryImpl继承SimpleJpaRepository,再修改配置使得SpringDataJPA自动创建出的所有实体类repository的实现代理子类都去继承我们的BaseRepositoryImpl,这样我们便能彻底实现扩展了。

前面说过SpringDataJPA会默认的将自动创建出的实现代理子类继承SimpleJpaRepository类,所以我们需要修改SimpleJpaRepository为我们自定义的BaseRepositoryImpl类,SpringDataJPA是通过JpaRepositoryFactoryBean来实现创建并继承过程的。我们只用自定义一个BaseRepositoryFactoryBean来继承JpaRepositoryFactoryBean,接下来只用修改最终返回功能对象,和确定功能对象的类型即可。最后记得要在spring的配置文件中在SpringDataJPA的配置中添加修改创建对象的factoryBean为我们自定义的BaseRepositoryFactoryBean。

最后,记得修改各实体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提供的功能已经足够强大了,但是依然还是不能满足实际开发中的所有需求
 * 所以希望在具有它功能的前提下再拓展一些功能
 * 之前是通过每个实体类的repository接口来直接继承JpaRepository接口,现在我们可以在中间添加一个父类接口BaseRepository
 * BaseRepository继承JpaRepository,再由实体类repository来继承BaseRepository
 * 这样就能够实现既实现了功能,又能随时扩展功能
 * @param <T>
 * @param <ID>
 */
@NoRepositoryBean
public interface BaseRepository<T,ID extends Serializable> extends JpaRepository<T,ID>,JpaSpecificationExecutor<T>{
    //根据Query拿到分页对象(分页)
    Page findPageByQuery(BaseQuery baseQuery);
    //根据Query拿到对应的所有数据(不分页)
    List<T> findByQuery(BaseQuery baseQuery);
    //根据jpql与对应的参数拿到数据
    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();
        //创建排序
        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);
    }
    /**
     *
     * 根据传入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;
/***
 *用于数据库操作
 */
public interface EmployeeRepository extends BaseRepository<Employee,Long> {
    /**
     * 可以自己扩展
     */
    List<Employee> findByUsernameLike(String username);
    /**
     * 使用@Query
     *  实现自己写JPQL查询
     */
    @Query("select o from Employee o where username like ?1")
    List<Employee> findByUsername(String username);
    /**
     * 当然也可以实现自己写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); //注:这里创建是我们的自定义类
    }
    //继承JpaRepositoryFactory后,把返回的对象修改成我们自己的实现
    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;
        }
        //这里返回最后的功能对象
        @Override
        protected Object getTargetRepository(RepositoryInformation information) {
            return new BaseRepositoryImpl<T,ID>((Class<T>)information.getDomainType(),entityManager);
        }
        //确定功能对象的类型
        @Override
        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
            return BaseRepositoryImpl.class;
        }
    }
}

spring配置文件中关于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"/>

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Spring Boot中使用Spring-data-jpa实现数据库增删查改

    在实际开发过程中,对数据库的操作无非就"增删改查".就最为普遍的单表操作而言,除了表和字段不同外,语句都是类似的,开发人员需要写大量类似而枯燥的语句来完成业务逻辑. 为了解决这些大量枯燥的数据操作语句,我们第一个想到的是使用ORM框架,比如:Hibernate.通过整合Hibernate之后,我们以操作Java实体的方式最终将数据改变映射到数据库表中. 为了解决抽象各个Java实体基本的"增删改查"操作,我们通常会以泛型的方式封装一个模板Dao来进行抽象简化,但是这

  • JPA之使用JPQL语句进行增删改查

    JPA支持两种表达查询的方法来检索实体和来自数据库的其他持久化数据:查询语句(Java Persistence Query Language,JPQL)和条件API(criteria API).JPQL是独立于数据库的查询语句,其用于操作逻辑上的实体模型而非物理的数据模型.条件API是根据实体模型构建查询条件 1.Java持久化查询语句入门 复制代码 代码如下: List<Person> persons= entityManager.createQuery("select p fro

  • spring-data-jpa实现增删改查以及分页操作方法

    有几个坑一定要注意: 实现删除操作的时候一定要在各层类中 增加 @Transactional 注释,否则会一直报错 在自己使用@Query定义操作时,会碰到编译器报错,这个时候只需要禁用QL的语法检查即可 以下是部分代码: //Repository package com.example.myproject.dao; import com.example.myproject.domain.User; import org.springframework.data.domain.Page; imp

  • Spring boot2+jpa+thymeleaf实现增删改查

    一.pom.xml引入相关模块web.jpa.thymeleaf.oracle: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot

  • JpaRepository如何实现增删改查并进行单元测试

    目录 JpaRepository增删改查进行单元测试 项目结构 单元测试 SpringDataJPA的Repository理解 repository抽取扩展理解 接下来贴一贴代码 JpaRepository增删改查进行单元测试 项目结构 创建UserInfoDaoI.java文件,继承JpaRepository.(不需要实现类) 根据条件查询/删除 更新 参考此文章进行开发 单元测试 SpringDataJPA的Repository理解 repository抽取扩展理解 在SpringDataJ

  • IntelliJ Idea SpringBoot 数据库增删改查实例详解

    SpringBoot 是 SpringMVC 的升级,对于编码.配置.部署和监控,更加简单 微服务 微服务是一个新兴的软件架构,就是把一个大型的单个应用程序和服务拆分为数十个的支持微服务.一个微服务的策略可以让工作变得更为简便,它可扩展单个组件而不是整个的应用程序堆栈,从而满足服务等级协议. Spring 为 微服务提供了一整套的组件-SpringClound , SpirngBoot 就是该基础. 第一个SpringBoot程序 这里使用的开发软件是IntelliJ Idea,和Eclipse

  • Springboot+hibernate实现简单的增删改查示例

    1.创建好项目之后在配置端口号(也可以不用配置,默认端口8080) #server server.port=8080 server.tomcat.uri-encoding=utf-8 2.配置mysql #MySQL spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8 sprin

  • spring-boot react如何一步一步实现增删改查

    1.maven继承spring-boot <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> <relativePath/> <!-- lookup parent from repos

  • SpringBoot+MySQL+Jpa实现对数据库的增删改查和分页详解

    一. 使用Springboot+Jpa实现对mysql数据库的增删改查和分页功能 JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中. 使用Springboot和jpa对数据库进行操作时,能够大大减少我们的工作量,在jpa中,已经在底层封装好了增删查的功能和sql语句,可以使我们进行快速开发 二.项目过程和配置文件 1.applaction.properties文件配置

  • springboot结合vue实现增删改查及分页查询

    1:首先.创建一个springboot项目,这里我使用以及构建好基本框架的脚手架,打开是这个样子: Result类:已经封装好了三种返回类型的包装类:code,msg,data 2:创建数据库叫mytest(可以自己取名字) CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '序号', `name` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL CO

  • SpringDataJPA详解增删改查操作方法

    目录 1.服务层调用dao继承的接口中的方法 2.使用jpql语句进行查询 3.可以引入原生的sql语句 4.根据jpa规定的特殊命名方法完成查询 5.动态查询 1.服务层调用dao继承的接口中的方法 dao层继承的继承JpaRepository和JpaSpecificationExecutor这两个接口,JpaRepository<操作的实体类, 主键类型> 封装了基本的curd操作,JpaSpecificationExecutor<操作的实体类类型> 封装了复杂的查询(分页.排

  • Springboot引入hibernate配置自动建表并进行增删改查操作

    目录 前言 一.引入依赖 二.配置yml 三.写代码 四.测试结果 前言 有些业务比较复杂,比如我们需要新建10张表,每张表有10个字段,如果用手工来操作,肯定非常浪费时间,而且随着代码中对实体类的修改,还要同时修改数据库表,有时候写着写着就忘了,代码改了,数据库没改,这种问题使用 hibernate 的自动建表就好啦. 一.引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifac

随机推荐