首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Hibernate 條件查詢分頁問題:新數據插入導致重複/遺漏解決方案

     編輯:程式設計綜合問答

問題場景

需求:按時間降序分頁查詢,但查詢過程中不斷有新數據插入。傳統 LIMIT offset, pageSize 會導致:

  • 第 1 頁:A, B
  • 插入新數據 N → 序列變 N, A, B, C, D, E
  • 第 2 頁原本應為 C, D,實際返回 D, E(C 重複、E 遺漏)

核心解決思路:游標分頁

不使用 OFFSET,改用 上一頁最後一條記錄的主鍵/時間戳 作為游標:

// 第一頁:無游標,按時間降序取前 N 條
SELECT * FROM table ORDER BY create_time DESC LIMIT 10;

// 後續頁:攜帶上一頁最後一條記錄的 create_time(或 id)
SELECT * FROM table 
WHERE create_time < :lastCreateTime  -- 嚴格小於,避免重複
ORDER BY create_time DESC LIMIT 10;

Hibernate 實現方式

1. Criteria API(舊版)

Criteria criteria = session.createCriteria(Entity.class);
criteria.addOrder(Order.desc("createTime"));
if (lastCreateTime != null) {
    criteria.add(Restrictions.lt("createTime", lastCreateTime));
}
criteria.setMaxResults(pageSize);
List<Entity> list = criteria.list();

2. JPA Specification / QueryDSL(推薦)

public Page<Entity> findByCursor(Date lastCreateTime, int pageSize) {
    Specification<Entity> spec = (root, query, cb) -> {
        List<Predicate> predicates = new ArrayList<>();
        if (lastCreateTime != null) {
            predicates.add(cb.lessThan(root.get("createTime"), lastCreateTime));
        }
        return cb.and(predicates.toArray(new Predicate[0]));
    };
    Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
    Pageable pageable = PageRequest.of(0, pageSize, sort);
    return repository.findAll(spec, pageable);
}

3. 原生 SQL + ScrollableResults(大數據量)

ScrollableResults scroll = session.createNativeQuery(sql)
    .setParameter("lastTime", lastCreateTime)
    .setMaxResults(pageSize)
    .scroll(ScrollMode.FORWARD_ONLY);
// 流式處理,避免全量加載

關鍵點總結

  1. 唯一且單調遞增/遞減的游標列:通常用主鍵 ID 或創建時間(需保證不重複,可組合 create_time, id)。
  2. 嚴格不等式:< 或 >,避免邊界重複。
  3. 不支持隨機跳頁:只能「下一頁」,適合無限滾動/列表流場景。
  4. 新數據不影響已讀頁面:因游標固定歷史位置。

替代方案對比

方案優點缺點
游標分頁無重複/遺漏、性能穩定不支持跳轉指定頁碼
OFFSET + 快照隔離級別支持隨機翻頁需數據庫支持可重複讀/快照隔離,高併發下鎖競爭大
標記已讀 ID 集合邏輯簡單內存開銷大,不適用長列表
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved