spring data jpa 动态分页查询实现

背景

之前使用JPA做动态分页都是使用的原生sql的IF实现。
在这里插入图片描述
乱吧?!乱是其次,最重要的是这么写无论如何都不会走索引的,数据量巨大时,慢的你怀疑人生。
最近有空研究了下使用@ManytoMany等等表关系注解实现联表查询。

开始

建资源组实体

@Entity(name = "base_resource_group")
@ApiModel(value = "资源组实体类")
public class ResourceGroupEntity implements Serializable {

    @Id
    @Column(name = "id",columnDefinition="int(11) COMMENT '资源组表'")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "group_name",columnDefinition="varchar(40) COMMENT '资源组名'")
    @ApiModelProperty(value = "资源组名")
    private String groupName;


....................................
}

资源实体

@Entity(name = "base_resources")
@ApiModel(value = "资源实体类")
public class ResourceEntity implements CycleLoadEntity  {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", columnDefinition="int(11) COMMENT '资源表'")
    private Integer id;

    @ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id", columnDefinition="int(11) COMMENT '父级id'")
    @JsonIgnoreProperties({"children"})
    private ResourceEntity parent;

    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
    @JsonIgnoreProperties({"parent"})
    private List<ResourceEntity> children;

    @ManyToOne(cascade = {CascadeType.PERSIST})
    @JoinColumn(name = "group_id")
    private ResourceGroupEntity group;

    @Column(name = "res_name", columnDefinition="varchar(40) COMMENT '资源名称'")
    @ApiModelProperty(value = "资源名称")
    private String resName;

    @Column(name = "res_link", columnDefinition="varchar(80) COMMENT '资源连接'")
    @ApiModelProperty(value = "资源连接")
    private String resLink;

    @Column(name = "description", columnDefinition="varchar(80) COMMENT '描述'")
    @ApiModelProperty(value = "描述")
    private String description;

    @Column(name = "enabled", columnDefinition="int(1) COMMENT '是否可用:0:可用;1:不可用'")
    @ApiModelProperty(value = "是否可用:0:可用;1:不可用")
    private Integer enabled;

    @Column(name = "is_open", columnDefinition="int(1) COMMENT '是否放开:0:不放开;1:放开'")
    @ApiModelProperty(value = "是否放开:0:不放开;1:放开")
    private Integer isOpen;

    @ManyToMany(mappedBy = "resources", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
    @JsonIgnoreProperties({"resources"})
    private Set<RoleEntity> roles;

    @Transient
    private boolean expand;

    @Transient
    private String title;

    @Transient
    private boolean checked;
    ...............................
    }

资源组与资源是一对多关系。

动态联查分页
    @Autowired
    ResourceRepository resourceRepository;
    @Autowired
    ResourceGroupRepository resourceGroupRepository;

    public Page<ResourceEntity> page(ResourcePageReqDTO resourcePageReqDTO) {
        Pageable pageable = PageUtil.getPage(resourcePageReqDTO);
        Specification<ResourceEntity> querySpecific = (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();
            //这里是重点,表关联起来
            Join<ResourceEntity, ResourceGroupEntity> group = root.join("group", JoinType.LEFT);
            Join<ResourceEntity, ResourceEntity> resJoin = root.join("parent", JoinType.LEFT);
            
            predicates.add(criteriaBuilder.isNull(resJoin.get("id")));
            predicates.add(criteriaBuilder.equal(root.get("enabled"), 0));
            if (resourcePageReqDTO.getResGroup() != null) {
                predicates.add(criteriaBuilder.equal(group.get("id"), resourcePageReqDTO.getResGroup()));
            }
            if (!StringUtils.isEmpty(resourcePageReqDTO.getResName())) {
                predicates.add(criteriaBuilder.like(root.get("resName"), "%" + resourcePageReqDTO.getResName() + "%"));
            }
            if (!StringUtils.isEmpty(resourcePageReqDTO.getResLink())) {
                predicates.add(criteriaBuilder.like(root.get("resLink"), "%" + resourcePageReqDTO.getResLink() + "%"));
            }
            Predicate[] predicate = new Predicate[predicates.size()];
            criteriaQuery.where(criteriaBuilder.and(predicates.toArray(predicate)));
            criteriaQuery.orderBy(criteriaBuilder.desc(root.get("id")));
            return criteriaQuery.getRestriction();
        };
        return resourceRepository.findAll(querySpecific, pageable);
    }

使用了表关系注解,那就涉及到了关系的删除、添加等,删除对象之前一定得先把关系删掉,写法和传统有些区别的,这类文章介绍很多就不写了。期间使用懒加载遇到了失效的问题,郁闷了半天,原来idea在debug模式下是不会懒加载的,都是即时加载。


版权声明:本文为weixin_45362084原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。