将ResultSet最有效地转换为JSON?
以下代码使用JSONArray
和JSONObject
将ResultSet
转换为JSONstring。
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; } }
- 有更快的方法吗?
- 有没有一种方法,使用更less的内存?
JIT编译器可能会做得很快,因为它只是分支和基本的testing。 你可以使用HashMap查找callback来更加优雅,但是我怀疑它会更快。 至于记忆,这是相当苗条的。
不知怎的,我怀疑这个代码实际上是内存或性能的关键瓶颈。 你有任何真正的理由去尝试优化它吗?
我认为有一种方法来使用更less的内存(一个固定的,而不是线性的数量取决于数据基数),但这意味着改变方法签名。 实际上,只要我们从ResultSet中获取Json数据,我们可能直接在输出stream上打印Json数据:已经写入的数据将被垃圾收集,因为我们不需要一个数组来保存它们。
我使用接受types适配器的GSON。 我写了一个types适配器来将ResultSet转换为JsonArray,它看起来非常喜欢你的代码。 我在等待2011年12月31日发布的“Gson 2.1:Targeted”版本,该版本将支持“支持用户定义的stream式适配器”。 然后,我将修改我的适配器为stream适配器。
更新
正如承诺我回来了,但不是与吉森,而是与jackson2.对不起,迟到(2年)。
前言:使用较less内存的关键是itsef在“服务器端”游标中。 有了这种游标(又称为Java开发的结果集),当客户端继续阅读时,DBMS将数据递增地发送到客户端(也称为驱动程序)。 我认为Oracle的游标是默认的服务器端。 对于MySQL> 5.0.2,请在连接url参数处查找useCursorFetch。 检查你最喜欢的DBMS。
1:所以要使用更less的内存,我们必须:
- 在场景后面使用服务器端游标
- 使用resultset作为只读 ,当然, 只转发 ;
- 避免加载列表(或
JSONArray
)中的所有游标,但直接写在输出行的每一行,其中输出线我的意思是输出stream或一个作家或一个JSON发生器,包装输出stream或作家。
2:正如jackson文件所言:
streamAPI是最好的performance(开销最低,读/写速度最快;其他两种方法build立在它上面)
3:我在你的代码中看到你使用getInt,getBoolean。 没有wasNull的ResultSet的getFloat … 我预计这会产生问题。
4:我使用数组来caching思考,并避免每次迭代调用getters。 虽然不是switch / case结构的粉丝,但是我用它来处理int
SQL Types
。
答案:还没有完全testing,它是基于jackson2.2 :
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.2.2</version> </dependency>
ResultSetSerializer
对象指示Jackson如何序列化(将对象转换为JSON)ResultSet。 它使用里面的Jackson Streaming API。 这里testing代码:
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);
而且,当然还有ResultSetSerializer类的代码:
public class ResultSetSerializer extends JsonSerializer<ResultSet> { public static class ResultSetSerializerException extends JsonProcessingException{ private static final long serialVersionUID = -914957626413580734L; public ResultSetSerializerException(Throwable cause){ super(cause); } } @Override public Class<ResultSet> 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); } } }
有两件事情会使这个更快:
将您的调用移出while循环中的rsmd.getColumnCount()
。 列数不应该在行之间变化。
对于每种列types,您最终都会调用如下所示的内容:
obj.put(column_name, rs.getInt(column_name));
使用列索引检索列值会稍微快一点:
obj.put(column_name, rs.getInt(i));
一个更简单的解决scheme(基于有问题的代码):
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;
你可以使用jOOQ来完成这项工作。 您不必使用jOOQ的所有function来利用一些有用的JDBC扩展。 在这种情况下,简单地写:
String json = DSL.using(connection).fetch(resultSet).formatJSON();
使用的相关API方法有:
-
DSLContext.fetch(ResultSet)
将JDBC ResultSet转换为jOOQ Result。 -
Result.formatJSON()
将jOOQ结果格式化为JSONstring。
结果格式如下所示:
{"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]]}
您也可以通过Result.map(RecordMapper)
轻松创build自己的格式,
这基本上和你的代码一样,避免了JSON对象的生成,直接“stream”到一个StringBuilder
。 我想说的是,在这两种情况下,性能开销应该可以忽略不计。
(免责声明:我为jOOQ背后的公司工作)
除了@Jim Cook提出的build议。 另一个想法是使用开关而不是if-elses:
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); switch( rsmd.getColumnType( i ) ) { case java.sql.Types.ARRAY: obj.put(column_name, rs.getArray(column_name)); break; case java.sql.Types.BIGINT: obj.put(column_name, rs.getInt(column_name)); break; case java.sql.Types.BOOLEAN: obj.put(column_name, rs.getBoolean(column_name)); break; case java.sql.Types.BLOB: obj.put(column_name, rs.getBlob(column_name)); break; case java.sql.Types.DOUBLE: obj.put(column_name, rs.getDouble(column_name)); break; case java.sql.Types.FLOAT: obj.put(column_name, rs.getFloat(column_name)); break; case java.sql.Types.INTEGER: obj.put(column_name, rs.getInt(column_name)); break; case java.sql.Types.NVARCHAR: obj.put(column_name, rs.getNString(column_name)); break; case java.sql.Types.VARCHAR: obj.put(column_name, rs.getString(column_name)); break; case java.sql.Types.TINYINT: obj.put(column_name, rs.getInt(column_name)); break; case java.sql.Types.SMALLINT: obj.put(column_name, rs.getInt(column_name)); break; case java.sql.Types.DATE: obj.put(column_name, rs.getDate(column_name)); break; case java.sql.Types.TIMESTAMP: obj.put(column_name, rs.getTimestamp(column_name)); break; default: obj.put(column_name, rs.getObject(column_name)); break; } } json.put(obj); }
这个答案可能不是最有效的,但它肯定是dynamic的。 将本地JDBC与Google的Gson库配对,我可以轻松地将SQL结果转换为JSONstream。
我已经包含了转换器,示例DB属性文件,SQL表生成和Gradle构build文件(使用依赖关系)。
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<List<Map<String, Object>>>() { 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<Map<String, Object>> select(Statement stmt, String query) throws SQLException { ResultSet resultSet = stmt.executeQuery(query); List<Map<String, Object>> records = mapRecords(resultSet); resultSet.close(); return records; } public static List<Map<String, Object>> mapRecords(ResultSet resultSet) throws SQLException { List<Map<String, Object>> records = new ArrayList<Map<String, Object>>(); ResultSetMetaData metaData = resultSet.getMetaData(); while (resultSet.next()) { records.add(mapRecord(resultSet, metaData)); } return records; } public static Map<String, Object> mapRecord(ResultSet resultSet, ResultSetMetaData metaData) throws SQLException { Map<String, Object> record = new HashMap<String, Object>(); 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' }
结果
基本的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
[ { "firstName": "John", "lastName": "Lennon", "age": 75 }, { "firstName": "Paul", "lastName": "McCartney", "age": 73 }, { "firstName": "George", "lastName": "Harrison", "age": 72 }, { "firstName": "Ringo", "lastName": "Starr", "age": 75 } ]
就像一个人一样,if / then循环比enums开关更有效率。 如果你有原始枚举整数的切换,那么它更有效率,但是对于variables,如果/ then更有效,至less对于Java 5,6和7来说。
也就是说,出于某种原因(经过一些性能testing)
if (ordinalValue == 1) { ... } else (ordinalValue == 2 { ... }
比…更快
switch( myEnum.ordinal() ) { case 1: ... break; case 2: ... break; }
我看到一些人怀疑我,所以我会在这里发布代码,以便能够运行自己以查看差异,以及从Java 7获得的输出。以下代码的结果包含10个枚举值,如下所示。 注意,这里的关键是if / then使用一个整数值与enum的序数常量进行比较,而对于原始int序数值的enum序数值的开关与针对每个枚举名称的enum开关进行比较。 如果/然后用一个整数值击败其他开关,尽pipe最后一个开关比第一个开关快一点,但它不比if / else快。
如果/其他花了23毫秒
开关花了45毫秒
开关2花了30毫秒
总计匹配: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); } }
首先预先生成列名,第二次使用rs.getString(i)
而不是rs.getString(column_name)
。
以下是这个的一个实现:
/* * 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<JSONObject> getFormattedResult(ResultSet rs) { List<JSONObject> resList = new ArrayList<JSONObject>(); try { // get column names ResultSetMetaData rsMeta = rs.getMetaData(); int columnCnt = rsMeta.getColumnCount(); List<String> columnNames = new ArrayList<String>(); 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; }
如果有人打算使用这个实现,你可能想检查一下 这个
这是我的转换代码的版本:
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; } }
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<String> data = new ArrayList<String>(); 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<String> columnNames = new ArrayList<String>(); 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<Map<String, String>> list = new ArrayList<Map<String, String>>(); 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);