Conversão mais eficiente de ResultSet para JSON?

O código a seguir converte um ResultSet em uma cadeia JSON usando JSONArray e JSONObject .

 import org.json.JSONArray; import org.json.JSONObject; import org.json.JSONException; import java.sql.SQLException; import java.sql.ResultSet; import java.sql.ResultSetMetaData; public class ResultSetConverter { public static JSONArray convert( ResultSet rs ) throws SQLException, JSONException { JSONArray json = new JSONArray(); ResultSetMetaData rsmd = rs.getMetaData(); while(rs.next()) { int numColumns = rsmd.getColumnCount(); JSONObject obj = new JSONObject(); for (int i=1; i<numColumns+1; i++) { String column_name = rsmd.getColumnName(i); if(rsmd.getColumnType(i)==java.sql.Types.ARRAY){ obj.put(column_name, rs.getArray(column_name)); } else if(rsmd.getColumnType(i)==java.sql.Types.BIGINT){ obj.put(column_name, rs.getInt(column_name)); } else if(rsmd.getColumnType(i)==java.sql.Types.BOOLEAN){ obj.put(column_name, rs.getBoolean(column_name)); } else if(rsmd.getColumnType(i)==java.sql.Types.BLOB){ obj.put(column_name, rs.getBlob(column_name)); } else if(rsmd.getColumnType(i)==java.sql.Types.DOUBLE){ obj.put(column_name, rs.getDouble(column_name)); } else if(rsmd.getColumnType(i)==java.sql.Types.FLOAT){ obj.put(column_name, rs.getFloat(column_name)); } else if(rsmd.getColumnType(i)==java.sql.Types.INTEGER){ obj.put(column_name, rs.getInt(column_name)); } else if(rsmd.getColumnType(i)==java.sql.Types.NVARCHAR){ obj.put(column_name, rs.getNString(column_name)); } else if(rsmd.getColumnType(i)==java.sql.Types.VARCHAR){ obj.put(column_name, rs.getString(column_name)); } else if(rsmd.getColumnType(i)==java.sql.Types.TINYINT){ obj.put(column_name, rs.getInt(column_name)); } else if(rsmd.getColumnType(i)==java.sql.Types.SMALLINT){ obj.put(column_name, rs.getInt(column_name)); } else if(rsmd.getColumnType(i)==java.sql.Types.DATE){ obj.put(column_name, rs.getDate(column_name)); } else if(rsmd.getColumnType(i)==java.sql.Types.TIMESTAMP){ obj.put(column_name, rs.getTimestamp(column_name)); } else{ obj.put(column_name, rs.getObject(column_name)); } } json.put(obj); } return json; } } 
  • Existe uma maneira mais rápida?
  • Existe uma maneira que usa menos memory?

O JIT Compiler provavelmente vai fazer isso muito rápido, já que são apenas ramificações e testes básicos. Você provavelmente poderia torná-lo mais elegante com uma pesquisa HashMap para um retorno de chamada, mas duvido que seria mais rápido. Quanto à memory, isso é muito magro como é.

De alguma forma, duvido que esse código seja, na verdade, um gargalo crítico para a memory ou o desempenho. Você tem algum motivo real para tentar otimizá-lo?

Eu acho que há uma maneira de usar menos memory (uma quantidade fixa e não linear dependendo da cardinalidade dos dados), mas isso implica em alterar a assinatura do método. Na verdade, podemos imprimir os dados do Json diretamente em um stream de saída, assim que os buscamos no ResultSet: os dados já gravados serão coletados como lixo, já que não precisamos de um array que os mantenha na memory.

Eu uso GSON que aceita adaptadores de tipo. Eu escrevi um adaptador de tipo para converter ResultSet para JsonArray e parece muito com o seu código. Estou aguardando o lançamento “Gson 2.1: Targeted Dec 31, 2011”, que terá o “Suporte para adaptadores de tipo de stream definidos pelo usuário”. Então modificarei meu adaptador para ser um adaptador de streaming.


Atualizar

Como prometi estou de volta, mas não com Gson, em vez com Jackson 2. Desculpe estar atrasado (de 2 anos).

Prefácio: A chave para usar menos memory do resultado itsef está no cursor “lado do servidor”. Com este tipo de cursores (também conhecido como resultset para Java devs), o SGBD envia dados incrementalmente para o cliente (também conhecido como driver) à medida que o cliente avança com a leitura. Eu acho que o cursor do Oracle são do lado do servidor por padrão. Para o MySQL> 5.0.2, procure por useCursorFetch no paramenter de url de conexão . Verifique o seu DBMS favorito.

1: Então, para usar menos memory, devemos:

  • usar o cursor do lado do servidor atrás da cena
  • use resultset aberto como somente leitura e, é claro, somente forward ;
  • evite carregar todo o cursor em uma lista (ou um JSONArray ), mas escreva cada linha diretamente em uma linha de saída , onde para linha de saída quero dizer um stream de saída ou um gravador ou também um gerador json que encapsula um stream de saída ou um gravador.

2: Como a documentação de Jackson diz:

A API de streaming tem melhor desempenho (menor sobrecarga, leitura / gravação mais rápida; outros 2 methods construídos sobre ela)

3: Eu vejo você no seu código use getInt, getBoolean. getFloat … do ResultSet sem wasNull . Eu espero que isso possa gerar problemas.

4: Eu usei arrays para cache pensa e evito chamar getters a cada iteração. Embora não seja fã do construtor switch / case, usei-o para esses Types SQL.

A resposta: ainda não totalmente testado, é baseado no Jackson 2.2 :

  com.fasterxml.jackson.core jackson-databind 2.2.2  

O object ResultSetSerializer instrui Jackson sobre como serializar (transformar o object em JSON) em ResultSet. Ele usa a API Jackson Streaming dentro. Aqui o código de um teste:

 SimpleModule module = new SimpleModule(); module.addSerializer(new ResultSetSerializer()); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(module); [ . . . do the query . . . ] ResultSet resultset = statement.executeQuery(query); // Use the DataBind Api here ObjectNode objectNode = objectMapper.createObjectNode(); // put the resultset in a containing structure objectNode.putPOJO("results", resultset); // generate all objectMapper.writeValue(stringWriter, objectNode); 

E, claro, o código da class ResultSetSerializer:

 public class ResultSetSerializer extends JsonSerializer { public static class ResultSetSerializerException extends JsonProcessingException{ private static final long serialVersionUID = -914957626413580734L; public ResultSetSerializerException(Throwable cause){ super(cause); } } @Override public Class handledType() { return ResultSet.class; } @Override public void serialize(ResultSet rs, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { try { ResultSetMetaData rsmd = rs.getMetaData(); int numColumns = rsmd.getColumnCount(); String[] columnNames = new String[numColumns]; int[] columnTypes = new int[numColumns]; for (int i = 0; i < columnNames.length; i++) { columnNames[i] = rsmd.getColumnLabel(i + 1); columnTypes[i] = rsmd.getColumnType(i + 1); } jgen.writeStartArray(); while (rs.next()) { boolean b; long l; double d; jgen.writeStartObject(); for (int i = 0; i < columnNames.length; i++) { jgen.writeFieldName(columnNames[i]); switch (columnTypes[i]) { case Types.INTEGER: l = rs.getInt(i + 1); if (rs.wasNull()) { jgen.writeNull(); } else { jgen.writeNumber(l); } break; case Types.BIGINT: l = rs.getLong(i + 1); if (rs.wasNull()) { jgen.writeNull(); } else { jgen.writeNumber(l); } break; case Types.DECIMAL: case Types.NUMERIC: jgen.writeNumber(rs.getBigDecimal(i + 1)); break; case Types.FLOAT: case Types.REAL: case Types.DOUBLE: d = rs.getDouble(i + 1); if (rs.wasNull()) { jgen.writeNull(); } else { jgen.writeNumber(d); } break; case Types.NVARCHAR: case Types.VARCHAR: case Types.LONGNVARCHAR: case Types.LONGVARCHAR: jgen.writeString(rs.getString(i + 1)); break; case Types.BOOLEAN: case Types.BIT: b = rs.getBoolean(i + 1); if (rs.wasNull()) { jgen.writeNull(); } else { jgen.writeBoolean(b); } break; case Types.BINARY: case Types.VARBINARY: case Types.LONGVARBINARY: jgen.writeBinary(rs.getBytes(i + 1)); break; case Types.TINYINT: case Types.SMALLINT: l = rs.getShort(i + 1); if (rs.wasNull()) { jgen.writeNull(); } else { jgen.writeNumber(l); } break; case Types.DATE: provider.defaultSerializeDateValue(rs.getDate(i + 1), jgen); break; case Types.TIMESTAMP: provider.defaultSerializeDateValue(rs.getTime(i + 1), jgen); break; case Types.BLOB: Blob blob = rs.getBlob(i); provider.defaultSerializeValue(blob.getBinaryStream(), jgen); blob.free(); break; case Types.CLOB: Clob clob = rs.getClob(i); provider.defaultSerializeValue(clob.getCharacterStream(), jgen); clob.free(); break; case Types.ARRAY: throw new RuntimeException("ResultSetSerializer not yet implemented for SQL type ARRAY"); case Types.STRUCT: throw new RuntimeException("ResultSetSerializer not yet implemented for SQL type STRUCT"); case Types.DISTINCT: throw new RuntimeException("ResultSetSerializer not yet implemented for SQL type DISTINCT"); case Types.REF: throw new RuntimeException("ResultSetSerializer not yet implemented for SQL type REF"); case Types.JAVA_OBJECT: default: provider.defaultSerializeValue(rs.getObject(i + 1), jgen); break; } } jgen.writeEndObject(); } jgen.writeEndArray(); } catch (SQLException e) { throw new ResultSetSerializerException(e); } } } 

Duas coisas que vão tornar isso mais rápido são:

Mova sua chamada para rsmd.getColumnCount() fora do loop while. A contagem de colunas não deve variar entre linhas.

Para cada tipo de coluna, você acaba chamando algo assim:

 obj.put(column_name, rs.getInt(column_name)); 

Será um pouco mais rápido usar o índice da coluna para recuperar o valor da coluna:

 obj.put(column_name, rs.getInt(i)); 

Uma solução mais simples (baseada no código em questão):

 JSONArray json = new JSONArray(); ResultSetMetaData rsmd = rs.getMetaData(); while(rs.next()) { int numColumns = rsmd.getColumnCount(); JSONObject obj = new JSONObject(); for (int i=1; i<=numColumns; i++) { String column_name = rsmd.getColumnName(i); obj.put(column_name, rs.getObject(column_name)); } json.put(obj); } return json; 

Você poderia usar o jOOQ para o trabalho. Você não precisa usar todos os resources do jOOQ para tirar proveito de algumas extensões JDBC úteis. Neste caso, basta escrever:

 String json = DSL.using(connection).fetch(resultSet).formatJSON(); 

Os methods relevantes da API usados ​​são:

  • DSLContext.fetch(ResultSet) para converter um ResultSet JDBC em um resultado jOOQ.
  • Result.formatJSON() para formatar o Resultado jOOQ em uma String JSON.

A formatação resultante ficará assim:

 {"fields":[{"name":"field-1","type":"type-1"}, {"name":"field-2","type":"type-2"}, ..., {"name":"field-n","type":"type-n"}], "records":[[value-1-1,value-1-2,...,value-1-n], [value-2-1,value-2-2,...,value-2-n]]} 

Você também pode criar sua própria formatação facilmente, através de Result.map(RecordMapper)

Isso essencialmente faz o mesmo que o seu código, contornando a geração de objects JSON, “streaming” diretamente em um StringBuilder . Eu diria que a sobrecarga de desempenho deve ser insignificante em ambos os casos, no entanto.

(Disclaimer: Eu trabalho para a empresa por trás do jOOQ)

Além das sugestões feitas pelo @Jim Cook. Um outro pensamento é usar um switch em vez de ifs elses:

 while(rs.next()) { int numColumns = rsmd.getColumnCount(); JSONObject obj = new JSONObject(); for( int i=1; i 

Essa resposta pode não ser a mais eficiente, mas com certeza é dinâmica. Emparelhando o JDBC nativo com a biblioteca Gson do Google, eu facilmente posso converter de um resultado SQL para um stream JSON.

Incluí o conversor, o arquivo de propriedades de database de exemplo, a geração de tabela SQL e um arquivo de compilation Gradle (com as dependencies usadas).

QueryApp.java

 import java.io.PrintWriter; import com.oracle.jdbc.ResultSetConverter; public class QueryApp { public static void main(String[] args) { PrintWriter writer = new PrintWriter(System.out); String dbProps = "/database.properties"; String indent = " "; writer.println("Basic SELECT:"); ResultSetConverter.queryToJson(writer, dbProps, "SELECT * FROM Beatles", indent, false); writer.println("\n\nIntermediate SELECT:"); ResultSetConverter.queryToJson(writer, dbProps, "SELECT first_name, last_name, getAge(date_of_birth) as age FROM Beatles", indent, true); } } 

ResultSetConverter.java

 package com.oracle.jdbc; import java.io.*; import java.lang.reflect.Type; import java.sql.*; import java.util.*; import com.google.common.reflect.TypeToken; import com.google.gson.GsonBuilder; import com.google.gson.stream.JsonWriter; public class ResultSetConverter { public static final Type RESULT_TYPE = new TypeToken>>() { private static final long serialVersionUID = -3467016635635320150L; }.getType(); public static void queryToJson(Writer writer, String connectionProperties, String query, String indent, boolean closeWriter) { Connection conn = null; Statement stmt = null; GsonBuilder gson = new GsonBuilder(); JsonWriter jsonWriter = new JsonWriter(writer); if (indent != null) jsonWriter.setIndent(indent); try { Properties props = readConnectionInfo(connectionProperties); Class.forName(props.getProperty("driver")); conn = openConnection(props); stmt = conn.createStatement(); gson.create().toJson(QueryHelper.select(stmt, query), RESULT_TYPE, jsonWriter); if (closeWriter) jsonWriter.close(); stmt.close(); conn.close(); } catch (SQLException se) { se.printStackTrace(); } catch (Exception e) { e.printStackTrace(); try { if (stmt != null) stmt.close(); } catch (SQLException se2) { } try { if (conn != null) conn.close(); } catch (SQLException se) { se.printStackTrace(); } try { if (closeWriter && jsonWriter != null) jsonWriter.close(); } catch (IOException ioe) { ioe.printStackTrace(); } } } private static Properties readConnectionInfo(String resource) throws IOException { Properties properties = new Properties(); InputStream in = ResultSetConverter.class.getResourceAsStream(resource); properties.load(in); in.close(); return properties; } private static Connection openConnection(Properties connectionProperties) throws IOException, SQLException { String database = connectionProperties.getProperty("database"); String username = connectionProperties.getProperty("username"); String password = connectionProperties.getProperty("password"); return DriverManager.getConnection(database, username, password); } } 

QueryHelper.java

 package com.oracle.jdbc; import java.sql.*; import java.text.*; import java.util.*; import com.google.common.base.CaseFormat; public class QueryHelper { static DateFormat DATE_FORMAT = new SimpleDateFormat("YYYY-MM-dd"); public static List> select(Statement stmt, String query) throws SQLException { ResultSet resultSet = stmt.executeQuery(query); List> records = mapRecords(resultSet); resultSet.close(); return records; } public static List> mapRecords(ResultSet resultSet) throws SQLException { List> records = new ArrayList>(); ResultSetMetaData metaData = resultSet.getMetaData(); while (resultSet.next()) { records.add(mapRecord(resultSet, metaData)); } return records; } public static Map mapRecord(ResultSet resultSet, ResultSetMetaData metaData) throws SQLException { Map record = new HashMap(); for (int c = 1; c <= metaData.getColumnCount(); c++) { String columnType = metaData.getColumnTypeName(c); String columnName = formatPropertyName(metaData.getColumnName(c)); Object value = resultSet.getObject(c); if (columnType.equals("DATE")) { value = DATE_FORMAT.format(value); } record.put(columnName, value); } return record; } private static String formatPropertyName(String property) { return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, property); } } 

database.properties

 driver=com.mysql.jdbc.Driver database=jdbc:mysql://localhost/JDBC_Tutorial username=root password= 

JDBC_Tutorial.sql

 -- phpMyAdmin SQL Dump -- version 4.5.1 -- http://www.phpmyadmin.net -- -- Host: 127.0.0.1 -- Generation Time: Jan 12, 2016 at 07:40 PM -- Server version: 10.1.8-MariaDB -- PHP Version: 5.6.14 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8mb4 */; -- -- Database: `jdbc_tutorial` -- CREATE DATABASE IF NOT EXISTS `jdbc_tutorial` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci; USE `jdbc_tutorial`; DELIMITER $$ -- -- Functions -- DROP FUNCTION IF EXISTS `getAge`$$ CREATE DEFINER=`root`@`localhost` FUNCTION `getAge` (`in_dob` DATE) RETURNS INT(11) NO SQL BEGIN DECLARE l_age INT; IF DATE_FORMAT(NOW(),'00-%m-%d') >= DATE_FORMAT(in_dob,'00-%m-%d') THEN -- This person has had a birthday this year SET l_age=DATE_FORMAT(NOW(),'%Y')-DATE_FORMAT(in_dob,'%Y'); ELSE -- Yet to have a birthday this year SET l_age=DATE_FORMAT(NOW(),'%Y')-DATE_FORMAT(in_dob,'%Y')-1; END IF; RETURN(l_age); END$$ DELIMITER ; -- -------------------------------------------------------- -- -- Table structure for table `beatles` -- DROP TABLE IF EXISTS `beatles`; CREATE TABLE IF NOT EXISTS `beatles` ( `id` int(11) NOT NULL, `first_name` varchar(255) DEFAULT NULL, `last_name` varchar(255) DEFAULT NULL, `date_of_birth` date DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Truncate table before insert `beatles` -- TRUNCATE TABLE `beatles`; -- -- Dumping data for table `beatles` -- INSERT INTO `beatles` (`id`, `first_name`, `last_name`, `date_of_birth`) VALUES(100, 'John', 'Lennon', '1940-10-09'); INSERT INTO `beatles` (`id`, `first_name`, `last_name`, `date_of_birth`) VALUES(101, 'Paul', 'McCartney', '1942-06-18'); INSERT INTO `beatles` (`id`, `first_name`, `last_name`, `date_of_birth`) VALUES(102, 'George', 'Harrison', '1943-02-25'); INSERT INTO `beatles` (`id`, `first_name`, `last_name`, `date_of_birth`) VALUES(103, 'Ringo', 'Starr', '1940-07-07'); /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 

build.gradle

 apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'application' mainClassName = 'com.oracle.jdbc.QueryApp' repositories { maven { url "http://repo1.maven.org/maven2" } } jar { baseName = 'jdbc-tutorial' version = '1.0.0' } sourceCompatibility = 1.7 targetCompatibility = 1.7 dependencies { compile 'mysql:mysql-connector-java:5.1.16' compile 'com.google.guava:guava:18.0' compile 'com.google.code.gson:gson:1.7.2' } task wrapper(type: Wrapper) { gradleVersion = '2.9' } 

Resultados

Basic SELECT

 [ { "firstName": "John", "lastName": "Lennon", "dateOfBirth": "1940-10-09", "id": 100 }, { "firstName": "Paul", "lastName": "McCartney", "dateOfBirth": "1942-06-18", "id": 101 }, { "firstName": "George", "lastName": "Harrison", "dateOfBirth": "1943-02-25", "id": 102 }, { "firstName": "Ringo", "lastName": "Starr", "dateOfBirth": "1940-07-07", "id": 103 } ] 

SELECT intermediário

 [ { "firstName": "John", "lastName": "Lennon", "age": 75 }, { "firstName": "Paul", "lastName": "McCartney", "age": 73 }, { "firstName": "George", "lastName": "Harrison", "age": 72 }, { "firstName": "Ringo", "lastName": "Starr", "age": 75 } ] 

Apenas como um heads up, o loop if / then é mais eficiente que o switch para enums. Se você tiver a opção com relação ao inteiro de enumeração bruto, será mais eficiente, mas contra a variável, se / então for mais eficiente, pelo menos para Java 5, 6 e 7.

Ou seja, por algum motivo (depois de alguns testes de desempenho)

 if (ordinalValue == 1) { ... } else (ordinalValue == 2 { ... } 

é mais rápido que

 switch( myEnum.ordinal() ) { case 1: ... break; case 2: ... break; } 

Vejo que algumas pessoas estão duvidando de mim, então vou postar código aqui que você pode executar para ver a diferença, juntamente com a saída que tenho do Java 7. Os resultados do código a seguir com 10 valores enum são os seguintes. Observe a chave aqui é o if / then usando um valor inteiro comparando contra constantes ordinais do enum, versus a opção com valor ordinal de um enum contra os valores ordinais int crus, versus um comutador com o enum contra cada nome de enum. O if / then com um valor inteiro bateu os dois outros switches, embora o último switch tenha sido um pouco mais rápido que o primeiro, não foi mais rápido que o if / else.

If / else levou 23 ms
Switch levou 45 ms
Interruptor 2 levou 30 ms
Correspondência total: 3000000

 package testing; import java.util.Random; enum TestEnum { FIRST, SECOND, THIRD, FOURTH, FIFTH, SIXTH, SEVENTH, EIGHTH, NINTH, TENTH } public class SwitchTest { private static int LOOP = 1000000; private static Random r = new Random(); private static int SIZE = TestEnum.values().length; public static void main(String[] args) { long time = System.currentTimeMillis(); int matches = 0; for (int i = 0; i < LOOP; i++) { int j = r.nextInt(SIZE); if (j == TestEnum.FIRST.ordinal()) { matches++; } else if (j == TestEnum.SECOND.ordinal()) { matches++; } else if (j == TestEnum.THIRD.ordinal()) { matches++; } else if (j == TestEnum.FOURTH.ordinal()) { matches++; } else if (j == TestEnum.FIFTH.ordinal()) { matches++; } else if (j == TestEnum.SIXTH.ordinal()) { matches++; } else if (j == TestEnum.SEVENTH.ordinal()) { matches++; } else if (j == TestEnum.EIGHTH.ordinal()) { matches++; } else if (j == TestEnum.NINTH.ordinal()) { matches++; } else { matches++; } } System.out.println("If / else took "+(System.currentTimeMillis() - time)+" ms"); time = System.currentTimeMillis(); for (int i = 0; i < LOOP; i++) { TestEnum te = TestEnum.values()[r.nextInt(SIZE)]; switch (te.ordinal()) { case 0: matches++; break; case 1: matches++; break; case 2: matches++; break; case 3: matches++; break; case 4: matches++; break; case 5: matches++; break; case 6: matches++; break; case 7: matches++; break; case 8: matches++; break; case 9: matches++; break; default: matches++; break; } } System.out.println("Switch took "+(System.currentTimeMillis() - time)+" ms"); time = System.currentTimeMillis(); for (int i = 0; i < LOOP; i++) { TestEnum te = TestEnum.values()[r.nextInt(SIZE)]; switch (te) { case FIRST: matches++; break; case SECOND: matches++; break; case THIRD: matches++; break; case FOURTH: matches++; break; case FIFTH: matches++; break; case SIXTH: matches++; break; case SEVENTH: matches++; break; case EIGHTH: matches++; break; case NINTH: matches++; break; default: matches++; break; } } System.out.println("Switch 2 took "+(System.currentTimeMillis() - time)+" ms"); System.out.println("Total matches: "+matches); } } 

Se alguém planeja usar essa implementação, talvez queira verificar isso e isso

Esta é a minha versão desse código de conversão:

 public class ResultSetConverter { public static JSONArray convert(ResultSet rs) throws SQLException, JSONException { JSONArray json = new JSONArray(); ResultSetMetaData rsmd = rs.getMetaData(); int numColumns = rsmd.getColumnCount(); while (rs.next()) { JSONObject obj = new JSONObject(); for (int i = 1; i < numColumns + 1; i++) { String column_name = rsmd.getColumnName(i); if (rsmd.getColumnType(i) == java.sql.Types.ARRAY) { obj.put(column_name, rs.getArray(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.BIGINT) { obj.put(column_name, rs.getLong(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.REAL) { obj.put(column_name, rs.getFloat(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.BOOLEAN) { obj.put(column_name, rs.getBoolean(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.BLOB) { obj.put(column_name, rs.getBlob(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.DOUBLE) { obj.put(column_name, rs.getDouble(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.FLOAT) { obj.put(column_name, rs.getDouble(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.INTEGER) { obj.put(column_name, rs.getInt(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.NVARCHAR) { obj.put(column_name, rs.getNString(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.VARCHAR) { obj.put(column_name, rs.getString(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.CHAR) { obj.put(column_name, rs.getString(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.NCHAR) { obj.put(column_name, rs.getNString(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.LONGNVARCHAR) { obj.put(column_name, rs.getNString(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.LONGVARCHAR) { obj.put(column_name, rs.getString(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.TINYINT) { obj.put(column_name, rs.getByte(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.SMALLINT) { obj.put(column_name, rs.getShort(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.DATE) { obj.put(column_name, rs.getDate(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.TIME) { obj.put(column_name, rs.getTime(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.TIMESTAMP) { obj.put(column_name, rs.getTimestamp(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.BINARY) { obj.put(column_name, rs.getBytes(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.VARBINARY) { obj.put(column_name, rs.getBytes(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.LONGVARBINARY) { obj.put(column_name, rs.getBinaryStream(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.BIT) { obj.put(column_name, rs.getBoolean(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.CLOB) { obj.put(column_name, rs.getClob(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.NUMERIC) { obj.put(column_name, rs.getBigDecimal(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.DECIMAL) { obj.put(column_name, rs.getBigDecimal(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.DATALINK) { obj.put(column_name, rs.getURL(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.REF) { obj.put(column_name, rs.getRef(column_name)); } else if (rsmd.getColumnType(i) == java.sql.Types.STRUCT) { obj.put(column_name, rs.getObject(column_name)); // must be a custom mapping consists of a class that implements the interface SQLData and an entry in a java.util.Map object. } else if (rsmd.getColumnType(i) == java.sql.Types.DISTINCT) { obj.put(column_name, rs.getObject(column_name)); // must be a custom mapping consists of a class that implements the interface SQLData and an entry in a java.util.Map object. } else if (rsmd.getColumnType(i) == java.sql.Types.JAVA_OBJECT) { obj.put(column_name, rs.getObject(column_name)); } else { obj.put(column_name, rs.getString(i)); } } json.put(obj); } return json; } } 

Primeiro, pré-gere os nomes das colunas, segundo use rs.getString(i) vez de rs.getString(column_name) .

O seguinte é uma implementação disso:

  /* * Convert ResultSet to a common JSON Object array * Result is like: [{"ID":"1","NAME":"Tom","AGE":"24"}, {"ID":"2","NAME":"Bob","AGE":"26"}, ...] */ public static List getFormattedResult(ResultSet rs) { List resList = new ArrayList(); try { // get column names ResultSetMetaData rsMeta = rs.getMetaData(); int columnCnt = rsMeta.getColumnCount(); List columnNames = new ArrayList(); for(int i=1;i<=columnCnt;i++) { columnNames.add(rsMeta.getColumnName(i).toUpperCase()); } while(rs.next()) { // convert each object to an human readable JSON object JSONObject obj = new JSONObject(); for(int i=1;i<=columnCnt;i++) { String key = columnNames.get(i - 1); String value = rs.getString(i); obj.put(key, value); } resList.add(obj); } } catch(Exception e) { e.printStackTrace(); } finally { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } return resList; } 
 package com.idal.cib; import java.io.FileWriter; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import org.json.simple.JSONArray; import org.json.simple.JSONObject; public class DBJsonConverter { static ArrayList data = new ArrayList(); static Connection conn = null; static PreparedStatement ps = null; static ResultSet rs = null; static String path = ""; static String driver=""; static String url=""; static String username=""; static String password=""; static String query=""; @SuppressWarnings({ "unchecked" }) public static void dataLoad(String path) { JSONObject obj1 = new JSONObject(); JSONArray jsonArray = new JSONArray(); conn = DatabaseConnector.getDbConnection(driver, url, username, password); try { ps = conn.prepareStatement(query); rs = ps.executeQuery(); ArrayList columnNames = new ArrayList(); if (rs != null) { ResultSetMetaData columns = rs.getMetaData(); int i = 0; while (i < columns.getColumnCount()) { i++; columnNames.add(columns.getColumnName(i)); } while (rs.next()) { JSONObject obj = new JSONObject(); for (i = 0; i < columnNames.size(); i++) { data.add(rs.getString(columnNames.get(i))); { for (int j = 0; j < data.size(); j++) { if (data.get(j) != null) { obj.put(columnNames.get(i), data.get(j)); }else { obj.put(columnNames.get(i), ""); } } } } jsonArray.add(obj); obj1.put("header", jsonArray); FileWriter file = new FileWriter(path); file.write(obj1.toJSONString()); file.flush(); file.close(); } ps.close(); } else { JSONObject obj2 = new JSONObject(); obj2.put(null, null); jsonArray.add(obj2); obj1.put("header", jsonArray); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (conn != null) { try { conn.close(); rs.close(); ps.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } @SuppressWarnings("static-access") public static void main(String[] args) { // TODO Auto-generated method stub driver = "oracle.jdbc.driver.OracleDriver"; url = "jdbc:oracle:thin:@localhost:1521:database"; username = "user"; password = "password"; path = "path of file"; query = "select * from temp_employee"; DatabaseConnector dc = new DatabaseConnector(); dc.getDbConnection(driver,url,username,password); DBJsonConverter formatter = new DBJsonConverter(); formatter.dataLoad(path); } } package com.idal.cib; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DatabaseConnector { static Connection conn1 = null; public static Connection getDbConnection(String driver, String url, String username, String password) { // TODO Auto-generated constructor stub try { Class.forName(driver); conn1 = DriverManager.getConnection(url, username, password); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return conn1; } } 

the other way , here I have used ArrayList and Map, so its not call json object row by row but after iteration of resultset finished :

  List> list = new ArrayList>(); ResultSetMetaData rsMetaData = rs.getMetaData(); while(rs.next()){ Map map = new HashMap(); for (int i = 1; i <= rsMetaData.getColumnCount(); i++) { String key = rsMetaData.getColumnName(i); String value = null; if (rsmd.getColumnType(i) == java.sql.Types.VARCHAR) { value = rs.getString(key); } else if(rsmd.getColumnType(i)==java.sql.Types.BIGINT) value = rs.getLong(key); } map.put(key, value); } list.add(map); } json.put(list);