2016-07-25 13 views
0

我嘗試使用hibernate的可滾動結果從參考this github項目從數據庫中獲取記錄,我試圖發送每個記錄作爲塊響應。如何從表中讀取所有記錄(> 1000萬條記錄)並將每條記錄作爲組塊響應提供?

控制器:

@Transactional(readOnly=true) 
public Result fetchAll() { 
    try { 
     final Iterator<String> sourceIterator = Summary.fetchAll(); 
     response().setHeader("Content-disposition", "attachment; filename=Summary.csv"); 

     Source<String, ?> s = Source.from(() -> sourceIterator); 
     return ok().chunked(s.via(Flow.of(String.class).map(i -> ByteString.fromString(i+"\n")))).as(Http.MimeTypes.TEXT); 

    } catch (Exception e) { 
     return badRequest(e.getMessage()); 
    } 
} 

服務:

public static Iterator<String> fetchAll() { 
    StatelessSession session = ((Session) JPA.em().getDelegate()).getSessionFactory().openStatelessSession(); 
    org.hibernate.Query query = session.createQuery("select l.id from Summary l") 
      .setFetchSize(Integer.MIN_VALUE).setCacheable(false).setReadOnly(true); 
    ScrollableResults results = query.scroll(ScrollMode.FORWARD_ONLY); 

    return new models.ScrollableResultIterator<>(results, String.class); 
} 

迭代:

public class ScrollableResultIterator<T> implements Iterator<T> { 
    private final ScrollableResults results; 
    private final Class<T> type; 

    public ScrollableResultIterator(ScrollableResults results, Class<T> type) { 
     this.results = results; 
     this.type = type; 
    } 

    @Override 
    public boolean hasNext() { 
     return results.next(); 
    } 

    @Override 
    public T next() { 
     return type.cast(results.get(0)); 
    } 
} 

對於測試的目的,我是ħ在我的表中有1007條記錄,每當我稱這個終點時,它總是隻返回503條記錄。

啓用AKKA日誌級別爲DEBUG並再次嘗試它,它會記錄以下行1007次 2016-07-25 19:55:38 +0530 [DEBUG] from org.hibernate.loader.Loader in application-akka.actor.default-dispatcher-73 - Result row:從日誌中我確認它獲取所有內容,但無法獲取剩餘的剩餘內容。

我在我的工作臺中運行相同的查詢,並將其導出到本地文件,並將其與端點生成的文件進行比較,保留從端點生成的LHS記錄和從Workbench導出的RHS文件。 第一行匹配,第二個和第三個不匹配。之後,直到最後,它纔得到替代記錄的匹配。

enter image description here

請糾正我,如果我做錯了什麼,並建議我這是用於生成CSV大型數據庫記錄的正確的做法。

爲了測試的目的,我刪除了上面代碼片段中的CSV轉換邏輯。

+1

接下來會有下一個呼叫。我會假設hasNext什麼也不做(即只檢查),而下一步推進內部光標? – rethab

回答

0
// Controller code 
// Prepare a chunked text stream 
ExportAsChuncked eac = new ExportAsChuncked(); 
response().setHeader("Content-disposition","attachment; filename=results.csv"); 
Chunks<String> chunks = new StringChunks() { 

    // Called when the stream is ready 
    public void onReady(Chunks.Out<String> out) { 
     try { 
      eac.exportData(scrollableIterator, out); 
     }catch (XOException e) { 
      Logger.error(ERROR_WHILE_DOWNLOADING_RESPONSE, e); 
     } 
     out.close(); 
    } 

}; 
// Serves this stream with 200 OK 
return ok(chunks); 


// Export as chunk logic 
class ExportAsChuncked { 
    void exportData(Iterator<String> data, Chunks.Out<String> out) { 
      while(data.hasNext()) { 
        out.write(data.next()); 
      } 
    } 
} 
相關問題