java - 如何在控制器层Spring进行流式传输
问题描述
我正在开发一个简单的 Java Spring 应用程序并尝试从数据库中获取所有保存的订单。尽管数据库中有大约 100k 条记录,但应用程序流程很简单。我在 JPA 层使用了从 DB 到应用程序数据的流式传输,效果很好。但是当这开始从控制器传输到客户端时,它会抛出 502 响应。以下是所有三层的代码。
有人可以帮助解决这个问题吗?要求所有这些数据都应该不使用任何过滤器或分页。
@GetMapping(produces = "application/json")
@ResponseStatus(HttpStatus.OK)
public Resources getOrders() {
return userService.getOrders();
}
@Transactional
public Resources getOrders() {
Stream<Orders> orders = streamAll();
List<Order> orderList = new ArrayList<>();
orderList.addAll(orderConverter.createFromEntities(orders));
Resource resources = new Resource();
resources.setResources(orderList);
return resources;
}
@Query("select u from Order")
Stream<Orders> streamAll();
解决方案
您收到 502 响应,因为您的 JVM 内存已耗尽。在存储库层使用流式分离对象。
首先,检查您的数据库是否支持通过流数据获取结果集。例如,MYSQL 支持它使用只读会话并使用值 Integer.MIN_VALUE [1] 获取大小。
稍后,自定义您的存储库以使用 StatelessSession 接口 [2] 打开无状态会话。多亏了这个接口,您可以分离对象,因此 Hibernate 会立即释放它,并且不会占用缓存中的内存。
如果您需要进行更改,请再次记住,您的对象是分离的。您需要打开另一个会话(读写)。您的对象将与这些会话一起保存,保存后,您必须手动将其分离。
此示例涵盖了第一个要求:
@PersistenceContext
private EntityManager entityManager;
public void stackoverflowQuestion() {
Session currentSession = entityManager.unwrap(Session.class);
ScrollableResults rows = currentSession
.createQuery("SELECT u FROM Order", Orders.class)
.setFetchSize(Integer.MIN_VALUE)
.scroll(ScrollMode.FORWARD_ONLY);
while (rows.next()) {
Orders order = (Orders) rows.get(0);
...
}
}
[1] https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-implementation-notes.html
[2] https://docs.jboss.org/hibernate/orm/3.5/reference/en-US/html/batch.html
推荐阅读
- java - java.sql.SQLException:关闭结果集:下一个
- list - 如何对列表进行排序
在 Dart 中以空对象结尾 - functional-programming - 如何将 Lisp/Scheme/Racket 符号放在末尾?
- azure - 如何在 Istio 中配置 Azure 应用网关
- python - 执行通常包含 '\;' 的 tmux 命令 使用 subprocess.run
- gcc - cmake - 预处理整个项目并将输出存储在文件中
- button - 按钮在可排序中无法正常工作
- c++ - 我使用 OpenMP 的线程越多,执行时间就越长,这是怎么回事?
- twig - 2D Twig Array - 动态打印内容
- android - 导航抽屉只需遵循一条指令