You're likely going to run into a number of limits trying to do this in a single HTTP request.
Streaming and asynchronous processing are two possible solutions.
Streaming
It looks like JPA 2.2 has added streaming support. To prevent out of memory conditions you'll likely need to tune your JVM, you'll also likely need to adjust the JDBC fetch size to balance your DB performance and your client performance.
You can then stream/buffer the results back to the client.
There are problems with this approach though. What happens when there's a momentary loss in the network connection? Someone accidentally closes their browser, providing Content-Length response headers to help gauge time remaining, etc.? A better approach is:
Asynchronous
The steps could go something like this:
- Client submits a request to the server.
- Server kicks off an asynchronous process (web worker or JMS).
- The async process generates the file and stores it temporarily on the file system.
- When the process completes it sends an email to the client to pick up their file. This is known as a claim check. Instead of an email, it could also be a URL that's returned that the user can then refresh to see when their file is ready for pick up.
- After a "reasonable" amount of time the file is deleted.
This approach can be configured to allow auto-resume capabilities and eliminates network uncertainty and browser tab closes from the equation. Overall, it also alleviate the strain of having to handle re-requests. Using JMS also, gives you the ability to scale this solution horizontally instead of vertically.