工作时发现oracle的分页查询的数据会重复,进行分析并给出解决方式

数据库用的是oracle的数据库,持久层框架是hibernate,分页查询用的是hql语句,方法是query.setFirstResults()和query.setMaxResults()

刚好leader要求写个postman自动化测试脚本验一下界面响应时间,于是做了几千条数据到数据库中。

在前端进行分页跳转的时候发现后面几页查询出来的数据总是相同的,当时就感到很奇怪,hql语句里有排过序呀,而且debug后台拿到前端传过来的分页参数,是正确的,并且每次分页参数不同但是仍然会查询出相同的数据

于是打开hibernate输出语句的功能,在经过hibernate解析后的sql语句如下。tempResults就是主体查询sql,太长了而且不方便贴出

    select
        * 
    from
        ( select
            row_.*,
            rownum rownum_ 
        from
            ( tempResults) row_ 
        where
            rownum <= ?
        ) 
    where
        rownum_ > ?

sql语句也是对的,是标准的分页语句。

为了验证可能是数据库解析语句导致的问题,我把sql放到plsql中执行,用前端传入的参数进行查询。

果真,虽然改动了查询参数,但是数据库中查出来的数据还是一模一样。因此可以判定是数据库在执行sql的时候出了这个问题。

于是上搜索引擎查询相关资料,发现这样的问题已经很多人问了,究其缘由就是oracle对rownum的语法规则的问题。(产生原因及解决方法的参考资料如下)

https://bbs.csdn.net/topics/300029848
https://bbs.csdn.net/topics/392190327?page=1
https://blog.csdn.net/f80407515/article/details/107654710
https://www.cnblogs.com/henuyuxiang/p/6674565.html
https://www.iteye.com/problems/68931

如果想要保证分页正常的运行,那么就要确保查询语句查询出来的数据是能确保唯一数据的。

虽然已经根据某个字段排过序了,但是该字段并不能确保唯一顺序,因为该字段不是主键也不是唯一键,多条数据的该字段值可以重复,那么oracle在排序时就不能确保唯一顺序值。

解决方法:所以在分页查询的时候必须确保唯一顺序,通常是对所查询的 主体数据 的非重复键(主键或者唯一键)进行排序。(注意:如果是联表数据的非重复键排序,要判断是否能查出唯一顺序,因为主体数据表很可能一对多,多对多联表数据,这样也是不能确保唯一顺序的)

解决原理:无论如何都要确保查询数据的唯一顺序,如果根据某个字段排序后仍不能确定唯一顺序,就要再加一个字段排序,以此类推,直到能确定唯一顺序为止,否则就有可能出现分页查询数据重复的情况

原文地址:https://www.cnblogs.com/skyvalley/p/15543110.html