JPA查询PostgreSQL行排序问题

文章目录

问题

  • 我们项目使用Spring Boot构建,使用JHipster生成业务代码,包含基础的增删改查代码
  • 使用PostgreSQL作为业务数据库,使用自动生成的JPA构建数据更新语查询
  • 在查询某个实体类的列表时,没有指定排序字段,查询返回按照添加顺序倒序返回,这样也符合我们的需求
  • 在修改了某个实体后,发现它在列表里的顺序变动了。顺序变动,没有固定排序,会对客户使用系统造成困惑
  • 一开始以为是在查询时加了修改时间倒序,查看代码后发现,没有更新时间字段,查询时也没有加排序字段
  • 这里放一段查询代码示例:
java 复制代码
		Specification<AreaConfig> specification = (Specification<AreaConfig>) (root, query, cb) ->
        {
            List<Predicate> predicateList = new ArrayList<>();
            Join<AreaConfig, SmartIntersection> join = root.join("smartIntersection", JoinType.LEFT);
            predicateList.add(cb.equal(join.get("id").as(Long.class), smartIntersection.getId()));
            Predicate[] pre = new Predicate[predicateList.size()];
            pre = predicateList.toArray(pre);
            return query.where(pre).getRestriction();
        };
        return areaConfigRepository.findAll(specification);

处理

  • 查阅文档之后知晓:使用SELECT语句查询表中的数据时,PostgreSQL不确保按照一定的顺序返回结果
  • 这就要求,查询时,如果想要每次都按照一定顺序返回,就要指定排序字段
  • 一种写法时,在调用Repository查询方法(如.findAll)时传递参数指定Sort,代码示例如下:
java 复制代码
        Specification<GreenWaveRouteConfig> specification = (Specification<GreenWaveRouteConfig>) (root, query, cb) ->
        {
            List<Predicate> predicateList = new ArrayList<>();
            Join<GreenWaveRouteConfig, GreenWaveRoute> join = root.join("greenWaveRoute", JoinType.LEFT);
            predicateList.add(cb.equal(join.get("id").as(Long.class), routeId));
            Predicate[] pre = new Predicate[predicateList.size()];
            pre = predicateList.toArray(pre);
            return query.where(pre).getRestriction();
        };
        return greenWaveRouteConfigRepository.findAll(specification, Sort.by("index"));
  • 另一种写法是,在specification里使用query.orderBy指定排序
java 复制代码
        Specification<SignalManualControlLog> specification = (root, query, cb) ->
        {
            List<Predicate> predicateList = new ArrayList<>();
            if (intersectionId != null) {
                predicateList.add(cb.equal(root.get("intersectionId").as(Long.class), intersectionId));
            }
            //时间倒序
            query.orderBy(cb.desc(root.get("opTime")));
            Predicate[] pre = new Predicate[predicateList.size()];
            pre = predicateList.toArray(pre);
            return query.where(pre).getRestriction();
        };
        List<SignalManualControlLog> controlLogs = manualControlLogRepository.findAll(specification);

PostgreSQL排序相关

  • 在一般情况下,PostgreSQL查询的结果集会按照指定的排序规则返回。如果你使用了ORDER BY子句,那么查询结果会按照该子句指定的排序规则返回。
  • 然而,在某些情况下,PostgreSQL返回结果可能不是按照期望的顺序。这通常是由于数据的物理存储方式、索引使用、并行查询或查询优化器等因素导致的。如果数据表上没有合适的索引或统计信息,PostgreSQL可能会选择不同的访问路径,导致结果的顺序与预期不符。
  • 为了确保结果按照指定的顺序返回,你可以使用ORDER BY子句明确指定排序规则。另外,你还可以考虑使用适当的索引或统计信息来帮助PostgreSQL优化查询执行计划,以确保结果按照预期的顺序返回。
  • 此外,PostgreSQL也提供了一些查询提示和指令,比如ORDER BY子句中的ORDER BY ... USING,以及SET命令中的random_page_cost等,可以用来影响PostgreSQL查询优化器的行为,以确保结果按照一定的顺序返回。
  • 总的来说,虽然在一般情况下PostgreSQL会按照指定的排序规则返回结果,但是在一些特殊情况下可能会出现结果顺序不符合预期的情况。因此,在编写查询语句时,应该使用ORDER BY子句来明确指定排序规则,以确保结果的顺序是可预测的。

JPA相关介绍

  • JPA(Java Persistence API)是一种用于管理Java应用程序中持久化数据的API。它为开发人员提供了一种方便的方法来在数据库中存储、检索和管理对象。在使用JPA的过程中,开发人员经常需要执行各种类型的查询来检索数据。以下是一些常见的JPA查询介绍:

    1. JPQL(Java Persistence Query Language)查询:JPQL是一种面向对象的查询语言,类似于SQL,但是针对实体对象进行查询。它使用实体类和其属性名称而不是表名和列名来执行查询。开发人员可以使用JPQL来执行复杂的查询操作,如连接查询、聚合函数、条件过滤等。
java 复制代码
TypedQuery<Customer> query = entityManager.createQuery("SELECT c FROM Customer c WHERE c.age > 18", Customer.class);
List<Customer> customers = query.getResultList();
    1. 命名查询:JPA还允许开发人员定义命名查询,以便在需要时轻松地引用和重用它们。开发人员可以在实体类上使用@NamedQuery注解来定义命名查询,然后在代码中使用实体管理器的createNamedQuery方法执行该命名查询。
java 复制代码
@NamedQuery(name="Customer.findAllAdults", query="SELECT c FROM Customer c WHERE c.age > 18")
public class Customer {
    //...
}

TypedQuery<Customer> query = entityManager.createNamedQuery("Customer.findAllAdults", Customer.class);
List<Customer> customers = query.getResultList();
    1. Criteria API查询:JPA还提供了Criteria API,它允许开发人员使用类型安全的查询构建器来动态地构建查询。Criteria API可以用于构建复杂的查询,而不需要编写任何字符串形式的查询语句。
java 复制代码
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Customer> query = cb.createQuery(Customer.class);
Root<Customer> root = query.from(Customer.class);
query.select(root).where(cb.greaterThan(root.get("age"), 18));
List<Customer> customers = entityManager.createQuery(query).getResultList();
  • 除了上述介绍的查询方式外,JPA还支持原生SQL查询、存储过程调用等其他查询方式。开发人员可以根据具体的业务需求选择适合的查询方式来操作持久化数据。
相关推荐
阳光九叶草LXGZXJ6 小时前
达梦数据库-报错-15-列【XXX】长度超出定义
linux·运维·数据库·sql·学习
字节渡客7 小时前
Redis键明明过期了,业务还在读到旧数据
数据库·redis·spring
OnlineProxy9 小时前
亚马逊多账号运营:如何在规避“关联封号”风险的同时实现电商规模化扩张
服务器·数据库·redis
辻弋20110 小时前
五年前的旅行视频糊成马赛克?Video2X用Real-ESRGAN逐帧重建细节,但只支持Windows、集显用户建议直接放弃
服务器·数据库·windows·游戏引擎·电脑
可乐鸡翅yeah_11 小时前
业务中 M3U8 水印相关坑,硬水印和动态水印区别
前端·网络·数据库·ffmpeg·m3u8在线
石头麻辣鱼11 小时前
Bamboo 调度系统 OceanBase 适配实战:存储过程迁移踩过的三个大坑
数据库
龙亘川12 小时前
数智驱动民政升级 精准守护民生保障
大数据·数据库·人工智能
念何架构之路12 小时前
zap扩展生态与总结
java·前端·数据库
晚安日记wanna13 小时前
MySQL 回表为什么这么慢?5 种优化手段逐个拆解
数据库·mysql·性能优化
第七页独白13 小时前
汽车零件厂如何通过 QMS 真正落地 IATF 16949——QMS软件系统:品质检验-内审稽核-8d客诉管理:全星质量管理软件系统
java·前端·数据库