Usar setFirstResult e setMaxResults é sua única opção que eu conheço.
Tradicionalmente, um conjunto de resultados rolável só transferiria linhas para o cliente conforme necessário. Infelizmente, o MySQL Connector/J realmente o falsifica, ele executa a consulta inteira e a transporta para o cliente, então o driver realmente tem todo o conjunto de resultados carregado na RAM e o alimentará por gotejamento (evidenciado por seus problemas de falta de memória) . Você teve a ideia certa, são apenas falhas no driver java do MySQL.
Eu não encontrei nenhuma maneira de contornar isso, então fui carregando grandes pedaços usando os métodos regulares setFirst/max. Desculpe ser o portador de más notícias.
Apenas certifique-se de usar uma sessão sem estado para que não haja cache de nível de sessão ou rastreamento sujo etc.
EDITAR:
Seu UPDATE 2 é o melhor que você obterá, a menos que você saia do MySQL J/Connector. Embora não haja motivo para que você não possa aumentar o limite da consulta. Desde que você tenha RAM suficiente para manter o índice, essa operação deve ser um pouco barata. Eu modificaria um pouco e pegaria um lote de cada vez e usaria o id mais alto desse lote para pegar o próximo lote.
Observação:isso só funcionará se other_conditions use igualdade (sem condições de intervalo permitidas) e tenha a última coluna do índice como id .
select *
from person
where id > <max_id_of_last_batch> and <other_conditions>
order by id asc
limit <batch_size>