Dopo aver letto this article, desidero utilizzare Spring per eseguire il flusso dei risultati della query del database direttamente su una risposta JSON per garantire l'utilizzo della memoria costante (nessun caricamento avido di un List
in memoria).Risorsa di chiusura del flusso con Spring MVC
Simile a quanto fatto nell'articolo con Hibernate, ho assemblato un oggetto greetingRepository
che restituisce un flusso del contenuto del database basato su un JdbcTemplate
. In tale implementazione, a creare un iteratore sulla interrogato ResultSet
, e torno il flusso come segue:
return StreamSupport.stream(spliterator(), false).onClose(() -> {
log.info("Closing ResultSetIterator stream");
JdbcUtils.closeResultSet(resultSet);
});
cioè con un metodo onClose()
garantire che il sottostante ResultSet
sarà chiusa se il flusso è dichiarata in un try-with-resources
costrutto :
try(Stream<Greeting> stream = greetingRepository.stream()) {
// operate on the stream
} // ResultSet underlying the stream will be guaranteed to be closed
Ma, come in questo articolo, voglio questo flusso per essere consumato da un mapper oggetto personalizzato (la maggiore MappingJackson2HttpMessageConverter
definito nell'articolo). Se prendiamo il try-with-resources
bisogno a parte, questo è fattibile come segue:
@RequestMapping(method = GET)
Stream<GreetingResource> stream() {
return greetingRepository.stream().map(GreetingResource::new);
}
Tuttavia, come un collega ha commentato in fondo a questo articolo, questo non si prende cura di chiudere le risorse di base.
Nel contesto di Spring MVC, come posso eseguire lo streaming dal database fino in fondo in una risposta JSON e comunque garantire che lo ResultSet
venga chiuso? Potresti fornire una soluzione di esempio concreta?
Non credo che il tuo problema sia una perdita di risorse: Spring sicuramente impegnerà la transazione e rilascerà la connessione, chiudendo in modo transitivo il tuo set di risultati. Ma mi aspetto il problema opposto: come gestisci che Connection sopravvive nel livello di visualizzazione? Mi affido a 'OpenSessionInViewInterceptor' per quello, che è specifico di Hibernate. –
A destra, nel mio scenario di test ho dimenticato di usare le transazioni, con loro non posso più eseguire lo streaming sul livello vista (inoltre uso MySQL, quindi sono sfortunato). Concludo che lo streaming al livello vista è allettante come potenzialmente efficiente e abbastanza elegante, ma purtroppo ancora difficile da usare nella pratica. –
Purtroppo, il supporto è ancora insufficiente. È la frontiera selvaggia. Spero che accada, però, perché le architetture Java sono state finora molto carenti in questo reparto. –