Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Postgres: getting an actual stream out of NamedParameterJdbcTemplate. #34648

Closed
garca7 opened this issue Mar 25, 2025 · 6 comments
Closed

Postgres: getting an actual stream out of NamedParameterJdbcTemplate. #34648

garca7 opened this issue Mar 25, 2025 · 6 comments
Labels
in: data Issues in data modules (jdbc, orm, oxm, tx) status: invalid An issue that we don't feel is valid

Comments

@garca7
Copy link

garca7 commented Mar 25, 2025

I'm using Postgres and I have a query whose result set is so large that does not fit into memory. When I call NamedParameterJdbcTemplate.queryForStream I get an out of memory error because the method attempts to read the whole result set before creating a stream based on the in-memory result.
Is there a way to get an actual stream out of the NamedParameterJdbcTemplate? I've managed to get something similar using a JDBC raw connection from Postgres (caveat: you need to disable auto commit for it to work) but in comparison is cumbersome not being able to use all the facilities provided by NamedParameterJdbcTemplate.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Mar 25, 2025
@quaff
Copy link
Contributor

quaff commented Mar 26, 2025

Have you tried jdbcTemplate.setFetchSize(fetchSize) ?

@jhoeller jhoeller added the in: data Issues in data modules (jdbc, orm, oxm, tx) label Mar 26, 2025
@jhoeller
Copy link
Contributor

queryForStream performs on-demand ResultSet access behind that stream, so it's primarily up to the JDBC driver how it actually reads the data. Whatever you did to a raw JDBC connection, you should also be able to set up on NamedParameterJdbcTemplate to make it interact with the JDBC driver the same way.

@garca7
Copy link
Author

garca7 commented Mar 31, 2025

Have you tried jdbcTemplate.setFetchSize(fetchSize) ?

I did. No difference

@garca7
Copy link
Author

garca7 commented Mar 31, 2025

queryForStream performs on-demand ResultSet access behind that stream, so it's primarily up to the JDBC driver how it actually reads the data. Whatever you did to a raw JDBC connection, you should also be able to set up on NamedParameterJdbcTemplate to make it interact with the JDBC driver the same way.

To enable the behaviour on raw JDBC I just had to call setAutoCommit(false) on the raw JDBC connection returned by jdbcTemplate.getDataSource().getConnection()

I'd appreciate some guidance on how to do this. The first problem I see is that Spring's JdbcTemplate seems to get its own connection from the data source, so I don't have a chance to change auto commit on the connection.

@quaff
Copy link
Contributor

quaff commented Mar 31, 2025

I'm pretty sure it's controlled by fetchSize, maybe Postgres requires autoCommit=false as prerequisite, you could configure your DataSource to disable auto commit.

See https://jdbc.postgresql.org/documentation/query/#example52setting-fetch-size-to-turn-cursors-on-and-off

@garca7
Copy link
Author

garca7 commented Apr 1, 2025

@quaff, you were in the end right. Setting the maxFetchSize value governs the creation of an actual stream of results from the database instead of streaming from an in-memory image of the results once all are retrieved.

However, simply setting the maxFetchSize value on an existing Spring-provided JdbcTemplate instance won't work when the NamedParameterJdbcTemplate is created based on the DataSource asscociated with the template, which is what I initially tried and the reason I said that there was no difference when changing that value.

You need to create the NamedParameterJdbcTemplate instance based on the that JDBC template instance. For example, given a Spring-provided JdbcTemplate instance template, the following code does create an actual stream of results fetching from Postgres on increments of 1000 rows:

jdbcTemplate.setMaxRows(1000);
var namedTemplate= new NamedParameterJdbcTemplate(jdbcTemplate);
var stream = namedTemplate.queryForStream(strQuery, params, this);

Closing the issue and thanks to everyone.

@garca7 garca7 closed this as completed Apr 1, 2025
@sbrannen sbrannen closed this as not planned Won't fix, can't repro, duplicate, stale Apr 1, 2025
@sbrannen sbrannen added status: invalid An issue that we don't feel is valid and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Apr 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: data Issues in data modules (jdbc, orm, oxm, tx) status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

5 participants