JPA 实现 增删改查

一 :使用JPA提供的基础CRUD操作
1.继承JPA提供的JpaRepository<T, ID>接口

/**
 * @Description
 */
@Repository
public interface KqGoodsRepository extends JpaRepository<KqGoods,Integer> {

}

JpaRepository<T, ID>接口提供了基本的crud操作,可以直接调用

 

public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    List<T> findAll();

    List<T> findAll(Sort var1);

    List<T> findAllById(Iterable<ID> var1);

    <S extends T> List<S> saveAll(Iterable<S> var1);

    void flush();

    <S extends T> S saveAndFlush(S var1);

    void deleteInBatch(Iterable<T> var1);

    void deleteAllInBatch();

    T getOne(ID var1);

    <S extends T> List<S> findAll(Example<S> var1);

    <S extends T> List<S> findAll(Example<S> var1, Sort var2);
}

2.编写cotroller、service调用响应的方法,进行crud操作
controller层代码:

 

    @GetMapping("/kqGoods/{number}")
    @ResponseBody
    public KqGoods getKqGoodsInformation(@PathVariable Integer number){
        Optional<KqGoods> kqGoods = kqGoodsService.selectKqGoods(number);
        if(kqGoods.isPresent()){
            return kqGoods.get();
        }else{
            return null;
        }
    }
    
    @GetMapping("/kqGoods")
    @ResponseBody
    public List<KqGoods> getKqGoodsInformation(){
        return  kqGoodsService.selectKqGoods();
    }

    @PostMapping("/kqGoods")
    @ResponseBody
    public KqGoods addKqGoodsInformation(KqGoods kqGoods){
        return kqGoodsService.insertKqGoods(kqGoods);
    }


    @PutMapping("/kqGoods")
    @ResponseBody
    public KqGoods updateKqGoodsInformation(KqGoods kqGoods){
        return kqGoodsService.updateKqGoods(kqGoods);
    }

    @DeleteMapping("/kqGoods/{number}")
    @ResponseBody
    public List<KqGoods> deleteKqGoodsInformation(@PathVariable Integer number){
        kqGoodsService.deleteKqGoods(number);
        return kqGoodsService.selectKqGoods();
    }

Service层代码:

 

/**
 * @Description
 */
public interface KqGoodsService {

     KqGoods insertKqGoods(KqGoods kqGoods);

     void deleteKqGoods(Integer number);

     KqGoods updateKqGoods(KqGoods kqGoods);

     List<KqGoods> selectKqGoods();

     Optional<KqGoods> selectKqGoods(Integer number);

}

 

/**
 * @Description
 */
@Service
public class KqGoodsServiceImpl implements KqGoodsService {
    @Autowired
    private KqGoodsRepository KqGoodsRepository;

    @Override
    public KqGoods insertKqGoods(KqGoods kqGoods) {
        return kqGoodsRepository.save(kqGoods);
    }

    @Override
    public void deleteKqGoods(Integer number) {
        KqGoodsRepository.deleteById(number);
    }

    @Override
    public KqGoods updateKqGoods(KqGoods kqGoods) {
        return kqGoodsRepository.save(kqGoods);
    }

    @Override
    public List<KqGoods> selectKqGoods() {
        return kqGoodsRepository.findAll();
    }

    @Override
    public Optional<KqGoods> selectKqGoods(Integer number) {
        return kqGoodsRepository.findById(number);
    }

}


二 :构建动态条件查询

JPA是支持动态查询的,需要我们的repository 继承JpaSpecificationExecutor接口,使用的时候传入相应参数即可。先看一下JpaSpecificationExecutor接口:

public interface JpaSpecificationExecutor<T> {
    Optional<T> findOne(@Nullable Specification<T> var1);

    List<T> findAll(@Nullable Specification<T> var1);

    Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);

    List<T> findAll(@Nullable Specification<T> var1, Sort var2);

    long count(@Nullable Specification<T> var1);
}

可以看到JpaSpecificationExecutor提供了五个方法,它们都必须传入的参数Specification<T> var1就是我们用来构建动态条件查询的关键。 其中,Pageable是分页查询用的,Sort是排序用的,这里先介绍Specification的使用。


public interface Specification<T> {
    Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
}

这里的参数Root<T> root负责实体类与数据表的映射 ,CriteriaBuilder cb负责构建查询语句, riteriaQuery<?> query负责执行查询语句,具体使用如下:
1.继承JpaSpecificationExecutor接口

@Repository
public interface KqGoodsRepository extends JpaRepository<KqGoods,Integer>, JpaSpecificationExecutor {

}

2.Service层加入动态条件查询方法的实现
service:

List<KqGoods> selectKqGoods(KqGoods kqGoods);

serviceImpl:

   @Override
    public List<KqGoods> selectKqGoods(KqGoods kqGoods) {
        Specification<KqGoods> query = new Specification<KqGoods>() {
            @Override
            public Predicate toPredicate(Root<KqGoods> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();
                if(kqGoods.getNumber()!=null){
                    predicates.add(criteriaBuilder.equal(root.get("number"),kqGoods.getNumber()));
                }
                if(StringUtils.isNotEmpty(kqGoods.getGender())){
                    predicates.add(criteriaBuilder.equal(root.get("gender"),kqGoods.getGender()));
                }
                if(StringUtils.isNotEmpty(kqGoods.getName())){
                    predicates.add(criteriaBuilder.like(root.get("name"),"%"+kqGoods.getName()+"%"));
                }
                if(StringUtils.isNotEmpty(kqGoods.getIdCard())){
                    predicates.add(criteriaBuilder.like(root.get("idCard"),"%"+kqGoods.getIdCard()+"%"));
                }
                if(StringUtils.isNotEmpty(kqGoods.getWorksName())){
                    predicates.add(criteriaBuilder.like(root.get("worksName"),"%"+kqGoods.getWorksName()+"%"));
                }
                if(StringUtils.isNotEmpty(kqGoods.getWorksType())){
                    predicates.add(criteriaBuilder.equal(root.get("worksType"),kqGoods.getWorksType()));
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
        return kqGoodsRepository.findAll(query);
    }

其中Root是查询的根对象,CriteriaBuilder可以用来构建查询关系。
predicates.add(criteriaBuilder.equal(root.get("number"),kqGoods.getNumber()))为例,
"number"指定了实体Player的属性number,通过root.get("number")获取实体属性number对应库表中的字段名称,kqGoods.getNumber()获取当前传入的查询条件值,equal指的是等于,criteriaBuilder将他们构建为对应的sql语句。此段代码的含义是where条件,如:number='19001'。(指定的属性名必须与查询实体的属性名一致,否则会报错。)相同的道理,predicates.add(criteriaBuilder.like(root.get("name"),"%"+kqGoods.getName()+"%"))即为模糊匹配。
最后return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]))返回Specification的实例,然后作为参数传入到kqGoodsRepository.findAll(query)中执行拼接好的动态条件查询。
当然criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]))取的and关系,还可以使用or,道理都一样。
3.Controller调用方法,用PostMan测试
controller:

    @GetMapping("/kqGoods")
    @ResponseBody
    public List<KqGoods> getKqGoodsInformation(KqGoods kqGoods){
        return  kqGoodsService.selectKqGoods(kqGoods);
    }

三 :构建排序和分页查询

我们在上面的动态分页查询的基础上增加分页查询的功能,先放更改后的代码。

 

    @Override
    public List<KqGoods> selectPlayer(KqGoods kqGoods, Integer page, Integer size) {
        Sort.Direction sort =  Sort.Direction.ASC;
        Pageable pageable = PageRequest.of(page-1, size, sort, "number");
        Specification<KqGoods> query = new Specification<KqGoods>() {
            @Override
            public Predicate toPredicate(Root<KqGoods> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();
                if(kqGoods.getNumber()!=null){
                    predicates.add(criteriaBuilder.equal(root.get("number"),kqGoods.getNumber()));
                }
                if(StringUtils.isNotEmpty(kqGoods.getName())){
                    predicates.add(criteriaBuilder.like(root.get("name"),"%"+kqGoods.getName()+"%"));
                }
                if(StringUtils.isNotEmpty(kqGoods.getIdCard())){
                    predicates.add(criteriaBuilder.like(root.get("idCard"),"%"+kqGoods.getIdCard()+"%"));
                }
                if(StringUtils.isNotEmpty(kqGoods.getWorksName())){
                    predicates.add(criteriaBuilder.like(root.get("worksName"),"%"+kqGoods.getWorksName()+"%"));
                }
                if(StringUtils.isNotEmpty(kqGoods.getWorksType())){
                    predicates.add(criteriaBuilder.equal(root.get("worksType"),kqGoods.getWorksType()));
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
        return kqGoodsRepository.findAll(query,pageable).getContent();
    }

我们使用的是JpaSpecificationExecutor提供的方法:

 

public interface JpaSpecificationExecutor<T> {
    Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);
}

Sort.Direction是个枚举有ASC(升序)和DESC(降序),Pageable pageable = PageRequest.of(page-1, size, sort, "number"); 获取PageRequest对象,page页码从0开始,size页容量,sort排序方式,以number为准进行排序。
Page接口如下:

public interface Page<T> extends Iterable<T> {
 
    int getNumber();            //当前第几页   返回当前页的数目。总是非负的
    int getSize();              //返回当前页面的大小。
    int getTotalPages();         //返回分页总数。
    int getNumberOfElements();   //返回当前页上的元素数。
    long getTotalElements();    //返回元素总数。
    boolean hasPreviousPage();  //返回如果有上一页。
    boolean isFirstPage();      //返回当前页是否为第一页。
    boolean hasNextPage();      //返回如果有下一页。
    boolean isLastPage();       //返回当前页是否为最后一页。
    Iterator<T> iterator();
    List<T> getContent();     //将所有数据返回为List
    boolean hasContent();     //返回数据是否有内容。
    Sort getSort();          //返回页的排序参数。
}

PS:实现多条件排序

Sort sort = new Sort(Sort.Direction.DESC, "createdate")
 .and(new Sort(Sort.Direction.AES, "id"));
Pageable pageable = new PageRequest(1, 10, sort)

四、使用@Query使用自定义的SQL语句
使用@Query注解,我们需要先了解它的参数:


@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@QueryAnnotation
@Documented
public @interface Query {
    String value() default "";
    String countQuery() default "";
    String countProjection() default "";
    boolean nativeQuery() default false;
    String name() default "";
    String countName() default "";
}

其中:
value 指定JPQL语句,当nativeQuery=true时是原生的sql语句
countQuery 指定count的JPQL语句,不指定则自动生成,当nativeQuery=true时是原生的sql语句,countQuery主要用来配合 value实现分页功能
countProjection 依据哪个字段来count一般默认即可
nativeQuery 默认是false,表示value 里面是不是原生的Sql 语句
name 指定一个query 的名字,必须是唯一的。 如果不指定,默认的生成规则是:{$domainClass}.${queryMethodName}
countName 指定一个countquery 名字,必须是唯一的。如果不指定,默认的生成规则是:{$domainClass}.${queryMethodName}.count
这里主要介绍常用的valuenativeQuery的使用。
1.一个使用@Query的简单例子(?n引入参数,参数顺序不可调换)

 

 @Query(value = "select k from KqGoods K where K.worksType = ?1 and K.age <= ?2 and K.gender = ?3")
    List<kqGoods> findByCondition(String worksType, Integer age, String gender);

 

 @Query(value = "select k.* from kqGoods k where k.works_type = ?1 and k.age <= ?2 and k.gender = ?3",nativeQuery = true)
    List<KqGoods> findByCondition(String worksType, Integer age, String gender);

以上是@Query的两种写法
第一种nativeQuery = false,使用基于实体的查询方式,from后面跟的是实体名,where后面的p.worksType对应的实体的字段;
第二种nativeQuery = true,使用基于数据表的查询方式,from后面跟的是表名,where后面的p.works_type对应的数据表中的列名;
2.Like表达式使用 (@Param注解注入参数,:引入参数,需要指定参数名)

 

 @Query(value = "select k from kqGoods k where k.worksName like %:worksName% and k.gender = :gender")
    List<kqGoods> findByCondition(@Param("worksName") String worksName, @Param("gender")String gender);

3.修改语句的自定义使用
@Query@Modifying同时使用用来自定义数据更改操作的SQL,@Transactional负责提交事务

 

   @Transactional
   @Query(value = "update KqGoods k set k.worksName = '拍摄的照片' where k.worksType =?1")
   @Modifying
   Integer updateByCondition(String worksType);

五、自定义返回实体
我们这里示例返回一个自定义的实体类Student
1.定义需要返回的实体(需要getset方法和全参构造器,这里使用lombok的注解实现);

 

@Data
@AllArgsConstructor
public class  Student {
    private String name;
    private String sex;
    private Integer age;
    private String school;
    private String speciality;
}

2.编写Repository

 

     /**
     * 返回自定义实体
     * @return
     */
    @Query(value = "select new com.example.bootstraptable.entity.Student(k.name,k.gender,k.age,k.school,k.speciality) from KqGoods k")
    List<Student> getStudents();

使用基于实体的查询来实现返回自定义实体
其中new com.example.bootstraptable.entity.Student(k.name,k.gender,k.age,k.school,k.speciality)Student的全参构造函数,使用com.example.bootstraptable.entity.Student引入实体类,相较于直接new Student(),使用包名引入更能准确的找到对应的返回实体。


七 :自定义语句实现分页查询

1.JPA持久层 InvoiceRepository.java

@Repository
public interface InvoiceRepository extends JpaRepository<Invoice, Integer> {
 
    @Query(
      value =
          "SELECT * from invoice_apply where company_id=?1 and IF (?2 is null ,1=1,status = ?2)",
      countQuery =
          "select count(*) from invoice_apply where company_id=?1 and IF (?2 is null ,1=1,status = ?2)",
      nativeQuery = true)
  Page<Map> findInvoice(int companyID, String status, Pageable pageable);
}

 

2.服务层

@Override
  public List findInvoice(int companyID, String status, Integer page, Integer pageSize) {
    Double amount = companyFinanceRepository.findDCompanyFinance(companyID);
    //分页查询
    Pageable pageable = PageRequest.of(page, pageSize, Sort.Direction.ASC, "id");
    Page<Map> invoiceList = invoiceRepository.findInvoice(companyID, status, pageable);
    return invoiceList.getContent();

}

 

 

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值