我尝试使用hibernate的可滚动结果从数据库中获取记录,并参考this github项目,我尝试将每条记录作为块响应发送。
控制器:
@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文件。 第一排比赛,第二排和第三排没有匹配。之后,它会获得备用记录的匹配,直到结束。
请纠正我,如果我做错了什么并建议我这是为大型数据库记录生成CSV的正确方法。
为了测试,我删除了上面代码段中的CSV转换逻辑。
答案 0 :(得分: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());
}
}
}