java 脑洞 - 开源模块 jpa-cquery 智能jpa查询

脑洞的由来

优化jpa查询,用简明的api来表达查询逻辑,最后还能生成查询语句的唯一识别,可用于查询缓存

更多demo请关注

springboot demo实战项目
java 脑洞
java 面试宝典
开源工具

maven 导入

        
            com.github.wqr503
            lp-jpa-cquery
            1.1.1
        

效果

比如我要查询调度任务(ScheduleTask),查询的条件是

  1. 任务有效 - invalid = false
  2. 任务名要对应 - taskName = test
  3. 任务的状态不是停止状态 - taskState != 0
  4. 任务下一次触发时间不为空- nextTriggerDate != null
  5. 任务根据创建时间排序 order by createTime
scheduleTaskDataDAO.findOne(CQ.from(ScheduleTask.class)
            .where()
            .eq(CQField.ofName("taskName"), test)
            .and()
            .eq(CQField.ofName("invalid"), false)
            .and()
            .not()
            .eq(CQField.ofName("taskState "), 0)
            .and()
            .isNotNull(CQField.ofName("nextTriggerDate"))
            .orderBy(CQField.ofName("createTime"))
            .build()
            .toSpecification());

看上去是不是简单易懂还容易操作

核心源码详解

jpa 提供的复杂查询接口 JpaSpecificationExecutor,通过封装构建jpa复杂查询的Predicate对象就能完成查询

/**
 * 语句实现类
 *
 * @author wqr
 * Created by on 2019/8/7
 */
class CQueryImpl implements CQuery, Specification {

    /**
     * 数据源类型
     */
    private Class fromClass;

    /**
     * 条件
     */
    private CQConditionPredicate condition;

    /**
     * 顺序
     */
    private List> orders;

    private String signKey;

    private CQueryImpl() {

    }

    static  CQueryImpl of(Class fromClass, @Nullable CQConditionPredicate condition,
        List> orders, String signKey) {
        CQueryImpl result = new CQueryImpl();
        result.fromClass = fromClass;
        result.condition = condition;
        result.orders = orders;
        result.signKey = signKey;
        return result;
    }

    @Override
    public Specification toSpecification() {
        return this;
    }

    @Override
    public String getSign() {
        return signKey;
    }

    @Override
    public String getSign(Pageable pageable) {
        return signKey + ",limit" + pageable.getPageNumber() + "-" + pageable.getPageSize();
    }

    @Override
    public String getShortSign(Pageable pageable) {
        return CodingAide.MD5(this.getSign(pageable));
    }

    @Override
    public String getShortSign() {
        return CodingAide.MD5(this.getSign());
    }

    @SuppressWarnings({"Duplicates", "NullableProblems"})
    @Override
    public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
        if (Objects.nonNull(condition)) {
            query.where(condition.toPredicate(root, query, cb));
        }
        if (!orders.isEmpty()) {
            List os = new ArrayList<>();
            for (CQOrder order : orders) {
                os.add(order.toOrder(root, query, cb));
            }
            query.orderBy(os);
        }
        return query.getRestriction();
    }

}

注意

该项目是对JpaSpecificationExecutor API 的封装,不支持子查询,不支持连表查询,微服务思想下应该要避免连表查询,更多应该通过模块间的级联查询完成,这个需要在微服务设计之初就考虑好。

备注

有同学在问,我能用cquery来求sum吗?要怎么做?
其实cquery定义是查询语句,和你求sum还是求max没直接关系,那具体要怎么做?可以参考JPA源码中JpaSpecificationExecutor 类的 long count(@Nullable Specification spec) API 的实现来自己封装sum和max方法,但是这是DAOManager要做的事,而不是cquery做的事, 所以这里只举例如何在调用count的时候用cquery

scheduleTaskDataDAO.count(CQ.from(ScheduleTask.class)
            .where()
            .eq(CQField.ofName("taskName"), test)
            .and()
            .eq(CQField.ofName("invalid"), false)
            .and()
            .not()
            .eq(CQField.ofName("taskState "), 0)
            .and()
            .isNotNull(CQField.ofName("nextTriggerDate"))
            .orderBy(CQField.ofName("createTime"))
            .build()
            .toSpecification());

获取源码

关注以下公众号, 回复"jpa-cquery"

#公众号
五分钟了解前沿技术,大数据,微服务,区域链,提供java前沿技术干货,独立游戏制作技术分享
五分钟技术

如果这篇文章对你有帮助请给个star
java 脑洞 - 开源模块 jpa-cquery 智能jpa查询_第1张图片

你可能感兴趣的:(java脑洞)