數據庫用的是oracle的數據庫,持久層框架是hibernate,分頁查詢用的是hql語句,方法是query.setFirstResults()和query.setMaxResults()
寫了一個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在排序時就不能確保唯一順序值。
解決方法:所以在分頁查詢的時候必須確保唯一順序,通常是對所查詢的 主體數據 的非重復鍵(主鍵或者唯一鍵)進行排序。(注意:如果是聯表數據的非重復鍵排序,要判斷是否能查出唯一順序,因為主體數據表很可能一對多,多對多聯表數據,這樣也是不能確保唯一順序的)
解決原理:無論如何都要確保查詢數據的唯一順序,如果根據某個字段排序后仍不能確定唯一順序,就要再加一個字段排序,以此類推,直到能確定唯一順序為止,否則就有可能出現分頁查詢數據重復的情況
