Springboot中使用SpringDataJPA三种查询方式 适用于联表多条件分页等

1. 标题

在日常开发中,随着Mybatis的流行,之前开发都是使用Mybatis。在新公司使用Spring Data Jpa,
通过该篇文章记录使用的相关情况和记录,用于巩固加深。

2.Spring Data JPA

	注意: 
	1.如果是查询直接使用@Query注解,如果是更新操作需要添加注解 @Modifying  
	2.如果联表查询需要获取两张表中的多个字段,可以使用map或者自定义一个Dto对象 
	3.分页对象参数

1.HQL语句查询

 在SpringDataJPA中,HQL语句操作的对象都是实体类对象,在HQL语句中返回的对象和条件都为实体类字段
 	1. 单表单条件查询
 	示例:  
 	@Query("select  实体类  from  实体类 where  name = :name ")
 	findByName(@Param("name ") String name ) 
 	如果存在多个参数,根据示例添加参数即可,实体类对象可以取别名,返回对象和实体类名称必须统一
 	要不都为别名,要不都为实体类对象
 	2.单表多条件查询
 	示例:
 		@Query("select  a  from  实体类 a where  a.name = :name  and a.age = :age ")
 	使用HQL语句进行查询需要注意关键字的使用,如果根据多条件查询  一般都使用findBy条件And条件And条件
 	示例:  
 		findByNameAndAge(@Param("name ") String name,@Param("age") String age) 
 		使用关键词JPA会自动拼装生成查询语句,提高开发效率,具体关键词可以参考SpringDataJPA官方文档
 	3. 联表多条件查询 
 	示例:
 		@Query(" select a from UserEntity a left join DeveloperEntity b on a.id = b.userId  
 			where  a.name   = :name and b.deleted = :deleted") 
 		findSend(@Param("name ") String name,@Param("deleted") String deleted)
	**但是需要注意的是HQL语句中条件都不能为空,必须确保参数必须存在**
	更新语句可以直接使用SpringDataJPA中自带的Save,delete,SaveAll等
	4. Dto对象的封装 
	示例:
	@Query(" select new Dto(a.id,a.name,b.name as debtName) from UserEntity a 
	left join DeveloperEntity b on a.id = b.userId  
 	where  a.name   = :name and b.deleted = :deleted") 
 	findSend(@Param("name ") String name,@Param("deleted") String deleted)
 	
 	Dto对象中字段的顺序需要和返回中的字段顺序一致,并提供全参构造器进行入参

2.原生SQL语句查询

	一般使用原生SQL语句都用于比较麻烦的联表多条件查询语句,因为HQL语句已经满足于一般的查询语句
	比如 高级查询  有的条件为空 有的条件不为空 一般都使用原生SQL语句或者Specification多条件查询
	示例: 
		@Query(value="select u.* from user u left join developer d on u.id = d.user_id 
		where a.name = :name and d,deleted = :deleted  
		and if(:userId is not null,a.user_id = :userId,1=1) ",
		countQuery="select count(u.id) from user u left join developer d on u.id = d.user_id 
		where a.name = :name and d,deleted = :deleted  
		and if(:userId is not null,a.user_id = :userId,1=1) ",nativeQuery = true)
		findSend(@Param("name ") String name,@Param("deleted") String deleted,@Param("userId") String userId)
	注意 
	1.如果使用原生SQL用于查询分页列表,countQuery建议都加上,因为实际项目中有时候出现过
	countQuery不存在报错的情况,有时候不加也可以
	2.使用原生SQL查询  SQL语句中使用都必须为数据库表名和字段,返回对象也为别名(表名).*。
	3. 如果使用原生SQL返回Dto对象和HQL语句中同理

3.Specification多条件查询

	使用Specification作为条件 代码的可读性和可维护性比较好,但是使用比较麻烦,具体使用倾向需要根据
	实际开发情况
	1.使用Specification其实就是使用SpringDataJPA的findAll查询 
	示例: 
	// 分页参数  和排序条件   Sort可多条件排序
	Pageable pageable = PageRequest.of(request.getPageNumber() - 1, request.getPageSize(),
            new Sort(Sort.Direction.DESC, "createTime"))
	findAll( 
		return (root, query, criteriaBuilder) -> {
        List ps = new ArrayList();
        QueryCaseInfoAction action = request.getData();
    	//添加不为空的条件
        ps.add(criteriaBuilder.equal(root.get("deleted"), DeletedType.NON));
        // 判断传入的条件是否为空  不为空才入参
        if(StringUtils.isNotBlank(contextTenantId)){
            ps.add(criteriaBuilder.equal(root.get("tenantId"), contextTenantId));
        }
        // 该条件用于  前端一个字段(后端数据库匹配多个条件的模糊查询)
        if (StringUtils.isNotBlank(fuzzyMatching)) {
            ps.add(criteriaBuilder.or
                    (criteriaBuilder.like(root.get("preCaseNum"), "%" + fuzzyMatching + "%"),
                    criteriaBuilder.like(root.get("caseNum"), "%" + fuzzyMatching + "%"),
                    criteriaBuilder.like(root.get("customerName"), "%" + fuzzyMatching + "%")));
        }
        //  实际查询
        if (startTime !=null && endTime !=null) {
            ps.add(criteriaBuilder.between(root.get("createTime"), startTime,endTime));
        }
        // 大于比较查询
        if (startTime !=null && endTime ==null) {
            ps.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), startTime));
        }
        // 小于比较查询
        if (startTime ==null && endTime !=null) {
            ps.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), endTime));
        }
		 // 联表查询
        if (StringUtils.isNotEmpty(state)) {
        	 //如果状态不为空
              predicateList.add(criteriaBuilder.equal(root.get("state").as(String.class), state));
          } 
          //创建联表查询对象
          Subquery subquery = query.subquery(String.class);
          // 需要关联的表实体类
          Root logRoot = subquery.from(ProcessLogEntity.class);
          // 构建查询语句
          subquery.select(logRoot.get("processId"))
          		//拼装条件
                  .where(criteriaBuilder.and(
                          criteriaBuilder.equal(logRoot.get("processId"), root.get("id")),
                          criteriaBuilder.equal(logRoot.get("auditorId"), userId)));
          // 添加关联表的查询语句到SQL中
          ps.add(criteriaBuilder.or(criteriaBuilder.exists(subquery),
                  criteriaBuilder.equal(root.get("starterId"), userId)));
    
        Predicate[] arr = new Predicate[ps.size()];
        return query.where(ps.toArray(arr)).getRestriction();
    }; pageable);

你可能感兴趣的:(SpringDataJpa,Springboot)