ResultSet을 JSON으로 가장 효율적으로 변환합니까?
는 을 합니다.ResultSet
를 사용하여 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<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;
}
}
- 더 빠른 방법은 없나요?
- 메모리 사용량을 줄일 수 있는 방법이 있나요?
메모리 사용량을 줄이는 방법(데이터 카디널리티에 따라 리니어 양이 아니라 고정)이 있다고 생각합니다만, 이것은 메서드의 시그니처를 변경하는 것을 의미합니다.실제로 Json 데이터를 ResultSet에서 가져오는 즉시 출력 스트림에 직접 인쇄할 수 있습니다.메모리에 보관하는 배열이 필요 없기 때문에 이미 작성된 데이터는 가비지 수집됩니다.
타입 어댑터를 지원하는 GSON을 사용하고 있습니다.ResultSet을 JsonArray로 변환하기 위해 타입 어댑터를 작성했는데 당신의 코드와 매우 흡사합니다.「Gson 2.1: Targeted Dec 31, 2011」릴리즈를 기다리고 있습니다.이 릴리즈에는 "사용자 정의 스트리밍 타입 어댑터 지원"이 포함되어 있습니다.그러면 어댑터를 스트리밍 어댑터로 수정하겠습니다.
갱신하다
약속대로 돌아왔는데 Gson이 아니라 Jackson 2와 함께.늦어서 죄송합니다.
서문:결과 메모리를 적게 사용하는 키는 "서버 측" 커서에 있습니다.이러한 종류의 커서(Java devs로 결과 집합)를 사용하면 DBMS는 클라이언트가 판독을 진행함에 따라 데이터를 클라이언트(드라이버)로 증분 전송합니다.Oracle 커서는 기본적으로 서버 쪽이라고 생각합니다.MySQL > 5.0.2의 경우 connection url paramenter에서 useCursorFetch를 찾습니다.마음에 드는 DBMS를 확인합니다.
1: 메모리 사용량을 줄이려면 다음 작업을 수행해야 합니다.
- 무대 뒤에서 서버 측 커서를 사용하다
- 결과 세트를 읽기 전용으로, 물론 전달 전용으로 사용합니다.
- 를 목록 목록)에.
JSONArray
각 행을 출력 라인에 직접 씁니다.출력 라인에 대해서는 출력 스트림 또는 라이터 또는 출력 스트림 또는 라이터를 랩하는 json 제너레이터를 의미합니다.
2: Jackson Documentation의 설명과 같이:
스트리밍 API가 가장 뛰어난 퍼포먼스(최저 오버헤드, 고속 읽기/쓰기, 기타 2가지 방법 구축)
3: getInt, getBoolean을 사용하는 코드에서 당신을 볼 수 있습니다.getFloat...resultSet의 wasNull을 사용하지 않습니다.이것이 문제를 일으킬 수 있을 것으로 예상합니다.
4: 어레이를 사용하여 사고를 캐시하고 반복할 때마다 게터를 호출하지 않도록 했습니다.스위치/케이스 구조의 팬은 아니지만, 그것을 위해 사용했습니다.int
SQLTypes
.
답변: 아직 완전히 테스트되지 않았습니다.Jackson 2.2에 근거하고 있습니다.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.2.2</version>
</dependency>
ResultSetSerializer
의 ResultSet.object를 으로 변환하는 방법을 합니다.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<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);
}
}
}
보다 심플한 솔루션(해당 코드 기준):
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;
이를 보다 빠르게 하기 위한 두 가지 사항은 다음과 같습니다.
을 「」로 이동합니다.rsmd.getColumnCount()
WHY ★★★★★★★★★★★★★★★★★★★★★★★.열 수는 행에 따라 달라지지 않아야 합니다.
각 열 유형에 대해 다음과 같은 호출이 발생합니다.
obj.put(column_name, rs.getInt(column_name));
열 인덱스를 사용하여 열 값을 검색하는 것이 약간 빠릅니다.
obj.put(column_name, rs.getInt(i));
JIT 컴파일러는 브랜치나 기본적인 테스트에 불과하기 때문에 아마 이 작업을 빠르게 진행할 수 있을 것입니다.콜백에 대한 HashMap 룩업을 통해 보다 우아하게 만들 수 있을 것입니다만, 더 빠른 것은 아닐까요.기억에 관해서는, 이것은 지금으로서는 꽤 슬림합니다.
왠지 이 코드가 기억력이나 성능에 중요한 병목인지 의심스럽다.최적화를 시도할 진짜 이유가 있습니까?
JSON 내보내기에 서드파티 라이브러리 사용
그 일에 jOOQ를 사용할 수 있습니다.유용한 JDBC 확장을 이용하기 위해 jOOQ의 모든 기능을 사용할 필요는 없습니다.이 경우는, 간단하게 다음과 같이 기입해 주세요.
String json = DSL.using(connection).fetch(resultSet).formatJSON();
사용되는 관련 API 메서드는 다음과 같습니다.
DSLContext.fetch(ResultSet)
JDBC ResultSet을 jOOQ 결과로 변환합니다.Result.formatJSON()
jOOQ 결과를 JSON 문자열로 포맷합니다.
그 결과 포맷은 다음과 같습니다.
{"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]]}
또, 독자적인 포맷을 간단하게 작성할 수도 있습니다.
코드와 오브젝트의 직접 JSON으로 StringBuilder
두 경우 모두 퍼포먼스 오버헤드는 무시할 수 있어야 합니다.
(면책자:jOOQ의 배후에 있는 회사에 근무하고 있습니다.)
대신 SQL/JSON 기능 사용
물론 미들웨어를 사용하여 JDBC ResultSets를 JSON에 매핑할 필요는 없습니다.이 질문에서는 이 작업을 수행해야 하는 SQL 방언에 대해서는 언급하지 않지만, 많은 경우 표준 SQL/JSON 구문 또는 이와 유사한 구문(예:
오라클
SELECT json_arrayagg(json_object(*))
FROM t
SQL Server
SELECT *
FROM t
FOR JSON AUTO
포스트그레스Ql
SELECT to_jsonb(array_agg(t))
FROM t
@Jim Cook의 제안과 함께.다른 하나는 if-eles가 아닌 스위치를 사용하는 것입니다.
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);
}
이 답변은 가장 효율적이지는 않지만 확실히 역동적입니다.네이티브 JDBC와 Google의 Gson 라이브러리를 페어링하면 SQL 결과에서 JSON 스트림으로 쉽게 변환할 수 있습니다.
변환기, DB 속성 파일 예, SQL 테이블 생성 및 Gradle 빌드 파일(의존 관계가 사용됨)을 포함했습니다.
Query App.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);
}
}
데이터베이스입니다.특성.
driver=com.mysql.jdbc.Driver
database=jdbc:mysql://localhost/JDBC_Tutorial
username=root
password=
JDBC_튜토리얼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'
}
결과.
기본 선택
[
{
"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
}
]
중간 선택
[
{
"firstName": "John",
"lastName": "Lennon",
"age": 75
},
{
"firstName": "Paul",
"lastName": "McCartney",
"age": 73
},
{
"firstName": "George",
"lastName": "Harrison",
"age": 72
},
{
"firstName": "Ringo",
"lastName": "Starr",
"age": 75
}
]
첫 번째 사전 생성 열 이름, 두 번째 사용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;
}
}
경고와 마찬가지로 if/then 루프가 enum 스위치보다 효율적입니다.raw enum 정수에 대해 스위치가 있는 경우 효율적이지만 변수에 대해 적어도 Java 5, 6, 및7의 경우 효율적입니다.
즉, 어떤 이유로 (일부 성능 테스트 후)
if (ordinalValue == 1) {
...
} else (ordinalValue == 2 {
...
}
보다 빠르다
switch( myEnum.ordinal() ) {
case 1:
...
break;
case 2:
...
break;
}
몇몇 사람들이 나를 의심하고 있는 것을 알 수 있기 때문에, 여기에 코드를 투고하고, 당신이 직접 실행해 차이를 확인할 수 있도록, Java 7로부터의 출력과 함께 합니다.10개의 enum 값을 갖는 다음 코드의 결과는 다음과 같습니다.여기서 중요한 것은 열거의 서수 상수와 비교한 정수 값을 사용하는 경우입니다.즉, raw inter 서수 값에 대한 열거 값의 스위치와 각 열거 이름에 대한 열거 값의 스위치입니다.if/then은 정수값을 사용하여 다른 두 스위치를 모두 제쳤지만 마지막 스위치는 첫 번째 스위치보다 조금 빨랐지만 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);
}
}
public static JSONArray GetJSONDataFromResultSet(ResultSet rs) throws SQLException {
ResultSetMetaData metaData = rs.getMetaData();
int count = metaData.getColumnCount();
String[] columnName = new String[count];
JSONArray jsonArray = new JSONArray();
while(rs.next()) {
JSONObject jsonObject = new JSONObject();
for (int i = 1; i <= count; i++){
columnName[i-1] = metaData.getColumnLabel(i);
jsonObject.put(columnName[i-1], rs.getObject(i));
}
jsonArray.put(jsonObject);
}
return jsonArray;
}
if-else 메쉬 솔루션을 선택한 모든 사용자는 다음을 사용하십시오.
String columnName = metadata.getColumnName(
String displayName = metadata.getColumnLabel(i);
switch (metadata.getColumnType(i)) {
case Types.ARRAY:
obj.put(displayName, resultSet.getArray(columnName));
break;
...
쿼리에 별칭이 있는 경우 열 이름과 열 레이블이 서로 다르기 때문입니다.예를 들어, 다음을 실행하는 경우:
select col1, col2 as my_alias from table
얻을 수 있을 것이다
[
{ "col1": 1, "col2": 2 },
{ "col1": 1, "col2": 2 }
]
대신:
[
{ "col1": 1, "my_alias": 2 },
{ "col1": 1, "my_alias": 2 }
]
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;
}
}
반대로 여기서는 ArrayList와 Map을 사용하고 있기 때문에 json 오브젝트를 행 단위로 호출하지 않고 결과 세트를 반복한 후에 호출합니다.
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);
언급URL : https://stackoverflow.com/questions/6514876/most-efficient-conversion-of-resultset-to-json
'source' 카테고리의 다른 글
선행 0을 사용하도록 mySQL MONTH()를 가져오시겠습니까? (0) | 2023.01.16 |
---|---|
Intelij IDEA 14 원격 저장소 자격 정보(인증) 변경 (0) | 2023.01.16 |
Java 7의 신기능 (0) | 2023.01.16 |
교착 상태 없이 행이 없는 경우 삽입 (0) | 2023.01.16 |
Panda DataFrame 열 목록 표시 (0) | 2023.01.06 |