java resultset转json_最有效的ResultSet转换为JSON?

问题

以下代码使用JSONArray和JSONObject将aResultSet转换为JSON字符串。

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

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;

}

}

-有更快的方法吗?

有没有一种使用更少内存的方法?

#1 热门回答(31 赞)

我认为有一种方法可以使用更少的内存(固定而非线性的数量取决于数据基数),但这意味着改变方法签名。实际上,我们可以在从ResultSet中获取Json数据时直接在输出流上打印Json数据:已经写入的数据将被垃圾收集,因为我们不需要将数据保存在内存中的数组。

我使用接受类型适配器的GSON。我写了一个类型适配器来将ResultSet转换为JsonArray,它看起来非常像你的代码。我正在等待"Gson 2.1:Targeted Dec 31,2011"发布,该版本将支持"支持用户定义的流式传输类型适配器"。然后我将修改我的适配器作为流适配器。

##更新

正如所承诺的那样,我回来了,但没有和Gson一起,而不是和Jackson 2.抱歉迟到了(2年)。

**前言:**使用较少内存的结果itsef在"服务器端"光标中的键。使用这种游标(a.k.a.结果集到Java开发人员),当客户端继续读取时,DBMS会逐步向客户端(a.k.a.驱动程序)发送数据。我认为默认情况下Oracle游标是服务器端。对于MySQL> 5.0.2,请查看useCursorFetch atconnection url paramenter。检查你最喜欢的DBMS。

**1:**为了减少使用内存,我们必须:

在场景后面使用服务器端光标

使用结果集打开为只读,当然,仅向前;

避免将所有光标加载到列表(或JSONArray)中,但直接在输出行上写入每一行,其中输出行I表示输出流或编写器或者包装输出流或写入器的json生成器。

**2:**正如Jackson文档所说:

Streaming API表现最佳(开销最低,读/写速度最快;其他2种方法基于它)

**3:**我在你的代码中看到你使用getInt,getBoolean。不带wasNull的ResultSet的getFloat ...我希望这会产生问题。

**4:**我使用数组来缓存think并避免每次迭代都调用getter。虽然不是开关/案例结构的粉丝,但我用它来表示intSQLTypes。

**答案:**尚未经过全面测试,是根据Jackson 2.2进行的:

com.fasterxml.jackson.core

jackson-databind

2.2.2

TheResultSetSerializerobject指示Jackson如何序列化(将对象转换为JSON)一个ResultSet。它使用内部的Jackson Streaming API。这里的测试代码:

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 {

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);

}

}

}

#2 热门回答(27 赞)

使这更快的两件事是:

将你的呼叫转移到while循环的rsmd.getColumnCount()out。列数不应在行之间变化。

对于每个列类型,你最终都会调用以下内容:

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

使用列索引检索列值会稍微快一些:

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

#3 热门回答(21 赞)

JIT编译器可能会非常快,因为它只是分支和基本测试。你可以通过HashMap查找回调来使它更优雅,但我怀疑它会更快。至于记忆,这是非常苗条的。

不知何故,我怀疑这段代码实际上是内存或性能的关键瓶颈。你有什么理由尝试优化吗?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值