我正在GETQuarkus 中實作一種方法,該方法應該向客戶端發送大量資料。使用JPA/Hibernate從資料庫中讀取資料,序列化為JSON,然后發送到客戶端。如果不將整個資料保存在記憶體中,如何有效地完成這項作業?我嘗試了以下三種可能性都沒有成功:
getResultList從 JPA使用并回傳一個Response串列作為正文。AMessageBodyWriter將負責將串列序列化為 JSON。但是,這會將所有資料拉入記憶體,這對于大量記錄是不可行的。getResultStream從 JPA使用并Response以流為主體回傳 a 。AMessageBodyWriter將負責將流序列化為 JSON。不幸的是,這不起作用,因為它似乎在EntityManagerJAX-RS 方法執行之后和MessageBodyWriter呼叫之前關閉。這意味著底層ResultSet也關閉了,作者不能再從流中讀取。- 使用 a
StreamingOutput作為Response主體。出現與 2. 相同的問題。
所以我的問題是:使用 Quarkus 發送通過 JPA 讀取的大資料的技巧是什么?
uj5u.com熱心網友回復:
您的結果是否必須全部集中在一個回應中?如何讓客戶端請求下一個結果頁面,直到沒有下一個頁面 - 一個典型的 REST API 分頁練習?此外,JPA 后端只會從資料庫中獲取該頁面,因此所有內容都不會留在記憶體中。
uj5u.com熱心網友回復:
這里有一些資源可以幫助您解決這個問題:
- 使用反應式休眠:https : //quarkusio.zulipchat.com/#narrow/stream/187030-users/topic/Large.20datasets.20using.20reactive.20SQL.20clients
- 分頁與僅前向結果集:https : //knes1.github.io/blog/2015/2015-10-19-streaming-mysql-results-using-java8-streams-and-spring-data.html
上一篇是針對SpringBoot的,不過這個想法也可以用Quarkus來實作。
- - - - - - 編輯:
好的,我已經找到了一個進行批量選擇的示例。我是用 Panache 完成的,但沒有它你也可以輕松完成。
我正在回傳一個 ScrollableResult,然后在 Rest 資源中使用它通過 SSE(服務器發送的事件)將它流式傳輸到客戶端。
@Entity
public class Fruit extends PanacheEntity {
public String name;
// I've removed the logic from here to the Rest resource,
// otherwise you cannot close the session
}
@Path("/fruits")
public class ReactiveFruitResource {
@GET
@Produces(SERVER_SENT_EVENTS)
public void fruitsStream(@Context Sse sse, @Context SseEventSink sink) {
var sf = Fruit.getEntityManager().getEntityManagerFactory().unwrap(SessionFactory.class);
try (var session = sf.openStatelessSession();
var scrollableResults = session.createQuery("select f from Fruit f").scroll(ScrollMode.FORWARD_ONLY)) {
while (scrollableResults.next()) {
sink.send(sse.newEventBuilder().data(scrollableResults.get(0)).mediaType(APPLICATION_JSON_TYPE).build());
}
sink.close();
}
}
}
然后我像這樣呼叫這個 Rest 端點(通過 httpie):
> http :8080/fruits --stream
data: {"id":9996,"name":"applecfcdd592-1934-4f0e-a6a8-2f88fae5d14c"}
data: {"id":9997,"name":"apple7f5045a8-03bd-4bf5-9809-03b22069d9f3"}
data: {"id":9998,"name":"apple0982b65a-bc74-408f-a6e7-a165ec3250a1"}
data: {"id":9999,"name":"apple2f347c25-d0a1-46b7-bcb6-1f1fd5098402"}
data: {"id":10000,"name":"apple65d456b8-fb04-41da-bf07-73c962930629"}
希望這對你有幫助。
uj5u.com熱心網友回復:
根據您的要求,您有兩種選擇:
選項 1:采用 HATEOAS 方法(https://restfulapi.net/hateoas/)。通過 REST 標準交換大型資料集的標準模式之一。因此,在這種方法中,服務器將在第一次回應中快速回應一組 HATEOAS URI。每個 HATEOAS URI 代表一組元素。因此,您需要根據資料大小生成這些 URI,并讓客戶端代碼負責將這些 URI 作為 REST API 單獨呼叫以獲取實際資料。但同樣在此選項中,您也可以考慮反應式風格,以通過較小的記憶體占用獲得更多的流式處理優勢。
選項 2:正如上面@Serkan 所建議的,不斷地將資料庫中的結果集作為 REST 回應傳輸到客戶端。這里需要確保客戶端和服務之間的網關進行超時設定。如果沒有網關你很好。因此,您可以在所有層利用反應式編程來實作連續流。“DAO/資料訪問層”-->“服務層”-->REST控制器-->客戶端。Spring reactor 也符合 JAX-RS。https://quarkus.io/guides/getting-started-reactive。這是處理大資料時最好的架構風格。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/372681.html
