Я пытаюсь создать приложение Java, которое может передавать очень большие результирующие наборы произвольных запросов SQL SELECT в файлы JSONL, в частности через SQLServer, но хотел бы работать с любым JDBC DataSource
. В Python это было бы легко просто обработать результат клиента SQL как генератор и затем вызвать json.dumps()
. Однако в этом коде кажется, что он помещает все в память перед записью, что обычно вызывает исключения из кучи и сборки мусора. Запросы, для которых нужно выполнить эти запросы, очень велики и возвращают до 10 ГБ необработанных данных. Время выполнения не является первостепенной задачей, если оно работает каждый раз.
Я пытался вызывать flush после любого ряда (что смешно), и это, кажется, помогает с маленькими наборами данных, но не с большими. Кто-нибудь может предложить стратегию, которую я могу использовать, чтобы легко это осуществить?
В моем клиентском классе SQL я использую Apache DbUtils QueryRunner
и MapListHandler
для создания списка Map
s, что является необходимой мне гибкостью (по сравнению с более традиционными подходами в Java, которые требуют указания схемы и типов):
public List<Map<String, Object>> query(String queryText) {
try {
DbUtils.loadDriver("com.microsoft.sqlserver.jdbc.Driver");
// this function just sets up all the connection properties. Ommitted for clarity
DataSource ds = this.initDataSource();
StatementConfiguration sc = new StatementConfiguration.Builder().fetchSize(10000).build();
QueryRunner queryRunner = new QueryRunner(ds, sc);
MapListHandler handler = new MapListHandler();
return queryRunner.query(queryText, handler);
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
return null;
}
}
JsonLOutputWriter
класс:
JsonLOutputWriter(String filename) {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.serializeNulls();
this.gson = gsonBuilder.create();
try {
this.writer = new PrintWriter(new File(filename), ENCODING);
} catch (FileNotFoundException | UnsupportedEncodingException e) {
e.printStackTrace();
}
}
void writeRow(Map row) {
this.writer.println(this.gson.toJson(row));
}
void flush() {
this.writer.flush();
}
Основной метод:
JsonLOutputWriter writer = new JsonLOutputWriter(outputFile)
for (Map row : client.query(inputSql)) {
writer.writeRow(row);
}
writer.flush()