使分页数据适应Java Stream

问题描述 投票:0回答:1

我想获取分页数据(从数据库)并将其调整为延迟加载的 Java Stream,以便我的 DAO 的客户端不需要担心页面索引、偏移量等。

我的设置如下:我有一个 DAO 方法,可以从数据库中获取数据页。具体来说,它使用MySQL SEEK来进行分页。即,要获取第 5 页,您需要向该方法提供第 4 页的最后一条记录。

使这种分页风格适应 Java Stream 的最简单方法是什么?对于我的用例来说,库很好,但框架(Spring、Androidx 等)则不然。

我的实现

我自己编写的实现如下。 (

Field
Record
Result
是JOOQ课程)

public abstract class PagedSeekIterator<K> implements Iterator<Record> {

   private K lastId = null;
   private boolean done = false;
   private Iterator<Record> currentIterator = null;
   private final Field<K> idField;

   public PagedSeekIterator(Field<K> idField) {
      this.idField = idField;
   }

   @Override
   public boolean hasNext() {
      if (done) {
         return false;
      }
      try {
         if (currentIterator == null) {
            // first call. Do init
            currentIterator = fetchWithSeek(lastId).iterator();
            return hasNext();
         }
         if (currentIterator.hasNext()) {
            return true;
         } else {
            // current page is read through. Fetch next page
            Result<Record> res = fetchWithSeek(lastId);
            if (res.isEmpty()) {
               // we're done here
               done = true;
               currentIterator = null;
               return false;
            } else {
               // next page looks good
               currentIterator = res.iterator();
               return true;
            }
         }
      } catch (SQLException e) {
         throw new SqlRuntimeException("Failed to fetch page", e);
      }
   }

   @Override
   public Record next() {
      if (!hasNext()) {
         throw new NoSuchElementException("We're done here.");
      }

      Record rec = currentIterator.next();
      lastId = rec.get(idField);
      return rec;
   }

   // lastId will be null on the first call
   protected abstract Result<Record> fetchWithSeek(K lastId) throws SQLException;
}

然后 Guava 可以方便地处理适应流:

Streams.stream(new PagedSeekIterator<Long>(Actions.ACTION.ID){
  // override fetchWithSeek()
});
// returns a lazy Stream<Record>

我的实现有效,但我忍不住觉得我在这里重新发明轮子。

我尝试过的其他事情

我也尝试过研究 AndroidX Paging,但是在 Android/Kotlin 上下文之外使用它是很痛苦的,而且我发现它增加了比我的普通 Java 项目减轻的复杂性更多的复杂性。

java mysql pagination java-stream jooq
1个回答
0
投票

这是我的图书馆abacus-jdbc的解决方案。

  1. 如果您想通过一次查询返回包含所有记录(页面)的

    stream
    并按流API拆分:

    JdbcUtil.prepareQuery(dataSource, sqlQuery)
          //.setParameters(...); // if needed
          stream(YourEntityClass.class); //.split(pageSize)
    
  2. 如果您想返回某个特定页面的

    stream
    (通过查找?)

    final String query = "select * from yourTable where someIdColumn > ? order by someIdColumn limit pageSize";
    JdbcUtil.prepareQuery(dataSource, query)
          .setLong(1, lastPageEndId);
          stream(YourEntityClass.class); // or stream(rowMapper);
    
  3. 如果您想退货

    stream
    。流中的每个元素都是一个
    page
    (记录列表),通过执行一次查询来加载:

     final String query = "select * from yourTable where someIdColumn > ? order by someIdColumn limit pageSize";
     JdbcUtil.queryByPage(dataSource, query, pageSize, (stmt, ret) -> stmt.setLong(1, ret == null ? startId : ret.get(ret.size() - 1).getId());
    
© www.soinside.com 2019 - 2024. All rights reserved.