ResultSet'in JSON'a en verimli şekilde dönüştürülmesi?


109

Aşağıdaki kod, ve ResultSetkullanarak bir JSON dizesine dönüştürür .JSONArrayJSONObject

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;
  }
}
  • Daha hızlı bir yol var mı?
  • Daha az bellek kullanmanın bir yolu var mı?


1
java.sql.Types.ARRAY uygulaması postgresql kullanarak benim için işe yaramadı (dizi "{...}" kullanılarak bir Dize olarak yerleştirildi. "obj.put (sütun_adı, rs.getArray (sütun_adı) satırının değiştirilmesi sona erdi ); "to" Array array = rs.getArray (column_name); if (array! = null) obj.put (column_name, new JSONArray (array.getArray ())); "
moleküler

Performans önemli bir sorunsa, bu JSON API'yi kullanmamalısınız, bunun yerine tüm verilerin bellek nesnelerini (ağaçta geriye bakabileceğiniz / bulabileceğiniz) bellek nesneleri oluşturmanıza gerek kalmadan yalnızca JSON yazan bir akış kitaplığı kullanmalısınız. Bununla birlikte, bunu yapmadan önce gerçekten bir performans sorununuz olduğundan emin olurum.
Sebastiaan van den Broek

3
Snippet'inizde bir hata var. java.sql.Types.BIGINT8 bayt boyutundadır, bu nedenle rs.getLong()notrs.getInt()
polarfish

3
Bunu yüklediğiniz için teşekkürler. Az önce bana saatlerce çalışmayı kurtardın.
DRich

Yanıtlar:


23

JIT Derleyicisi, sadece dallar ve temel testler olduğu için muhtemelen bunu oldukça hızlı yapacak. Bir geri arama için HashMap aramasıyla muhtemelen daha zarif hale getirebilirsiniz, ancak daha hızlı olacağından şüpheliyim. Hafızaya gelince, bu olduğu gibi oldukça zayıf.

Bir şekilde bu kodun bellek veya performans için kritik bir dar boğaz olduğundan şüpheliyim. Optimize etmeye çalışmak için gerçek bir sebebiniz var mı?


Kaynak kodunu açık kaynaklı bir çerçeveye koyuyorum, bu yüzden ne için kullanılacağını bilmiyorum. Bu nedenle mümkün olduğunca verimli hale getirmeye çalışıyorum.
Devin Dixon

1
@DevinDixon: çerçeve mevcut mu? Sorunuzdaki koda benzer bir yerde bir açık kaynak kod deposunda zaten mevcut olan bir şey var mı?

34

Sanırım daha az bellek kullanmanın bir yolu var (veri önemliliğine bağlı olarak sabit ve doğrusal olmayan bir miktar), ancak bu yöntem imzasını değiştirmeyi gerektiriyor. Aslında, Json verilerini ResultSet'ten alır almaz doğrudan bir çıktı akışına yazdırabiliriz: önceden yazılmış veriler, onları bellekte tutan bir diziye ihtiyacımız olmadığı için çöp toplanacaktır.

Tip adaptörlerini kabul eden GSON kullanıyorum. ResultSet'i JsonArray'e dönüştürmek için bir tür bağdaştırıcısı yazdım ve kodunuza çok benziyor. "Kullanıcı tanımlı akış tipi bağdaştırıcıları için destek" olacak "Gson 2.1: Hedeflenen 31 Aralık 2011" sürümünü bekliyorum. Sonra adaptörümü akış adaptörü olarak değiştireceğim.


Güncelleme

Söz verdiğim gibi geri döndüm ama Gson ile değil, Jackson 2 ile. Geç kaldığım için özür dilerim (2 yıl).

Önsöz: Sonuçta daha az bellek kullanmanın anahtarı "sunucu tarafı" imlecindedir. Bu tür imleçlerle (diğer adıyla Java geliştiricilerine sonuç kümesi), DBMS, istemci okumaya devam ederken veriyi artımlı olarak istemciye (sürücü olarak da bilinir) gönderir. Oracle imlecinin varsayılan olarak sunucu tarafında olduğunu düşünüyorum. MySQL> 5.0.2 için bağlantı url parametresinde useCursorFetch'i arayın . En sevdiğiniz DBMS'yi kontrol edin.

1: Daha az bellek kullanmak için şunları yapmalıyız:

  • sahnenin arkasında sunucu tarafı imleci kullan
  • sonuç kümesini salt okunur olarak açın ve elbette yalnızca ileriye doğru kullanın ;
  • tüm imleci bir listeye (veya a JSONArray) yüklemekten kaçının, ancak her satırı doğrudan bir çıktı satırına yazın , burada çıkış satırı için bir çıktı akışı veya bir yazıcı veya bir çıktı akışını veya bir yazıcıyı saran bir json oluşturucuyu kastediyorum.

2: Jackson Documentation'ın dediği gibi:

Streaming API en iyi performans gösterir (en düşük ek yük, en hızlı okuma / yazma; üzerine inşa edilen diğer 2 yöntem)

3: Kodunuzda getInt, getBoolean kullandığınızı görüyorum. olmadan ResultSet ait getFloat ... wasNull . Bunun sorun yaratacağını umuyorum.

4: Düşünceleri önbelleğe almak ve her yinelemede alıcıları çağırmamak için diziler kullandım. Switch / case yapısının hayranı olmasa da, onu intSQL için kullandım Types.

Cevap: Henüz tam olarak test edilmedi, Jackson 2.2'ye dayanıyor :

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.2.2</version>
</dependency>

ResultSetSerializerNesne serialize bir ResultSet (JSON nesneyi Dönüşümü) nasıl Jackson talimat verir. İçinde Jackson Streaming API'sini kullanır. İşte bir testin kodu:

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

Ve tabii ki ResultSetSerializer sınıfının kodu:

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

27

Bunu hızlandıracak iki şey:

Çağrınızı rsmd.getColumnCount()while döngüsünün dışına taşıyın . Sütun sayısı satırlar arasında değişmemelidir.

Her sütun türü için, şu şekilde bir şey çağırırsınız:

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

Sütun değerini almak için sütun dizini kullanmak biraz daha hızlı olacaktır:

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

Ayrıca String column_name;while döngüsünün dışında tanımlayın .
Charney Kaye

22

Daha basit bir çözüm (söz konusu koda göre):

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;

3
güzel, ancak DATETIME ve TIMESTAMP ile ilgili bir hata var (Kesme
işaretlerini eklemiyor

güzel ve basit
Anoop LL

10

Bu iş için jOOQ'u kullanabilirsiniz . Bazı yararlı JDBC uzantılarından yararlanmak için jOOQ'nun tüm özelliklerini kullanmak zorunda değilsiniz. Bu durumda şunu yazın:

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

Kullanılan ilgili API yöntemleri şunlardır:

Ortaya çıkan biçimlendirme şöyle görünecektir:

{"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]]}

Ayrıca, kendi biçimlendirmenizi oldukça kolay bir şekilde oluşturabilirsiniz. Result.map(RecordMapper)

Bu, esasen kodunuzla aynı şeyi yapar, JSON nesnelerinin oluşturulmasını engelleyerek, doğrudan bir StringBuilder. Yine de, performans ek yükünün her iki durumda da ihmal edilebilir olması gerektiğini söyleyebilirim.

(Sorumluluk reddi: jOOQ'un arkasındaki şirket için çalışıyorum)


Bu harika ama sonuçta ortaya çıkan dizeyi ayrıştırmada sorunlar yaşıyorum. Değerlerden bazıları bir tırnak işareti içerdiğinde ayrıştırıcı doğru şekilde çalışamaz: Geçerli bir JSON dizesi oluşturmak "için değerlerin içindeki tırnak işaretlerinin öncelenmesi gerektiğini düşünüyorum \". Bu, formatJSON()işlevin bir hatası mı ? Yoksa bir şey mi kaçırıyorum?
Oneiros

@Oneiros: jOOQ bu tırnak işaretlerinden doğru bir şekilde kaçmalı ... En iyisi yeni bir soru sorun (ayrıntılarla birlikte) veya bir hata bildirin
Lukas Eder

Örneğinizde resultSet ne için kullanılıyor fetch(resultSet)? Hiçbir yerde tanımlanmadı. Ve eğer alma işleminden ResultSetönce JDBC alırsam, bunun amacı DSL.using(connection)nedir? Neden bağlantıya ihtiyacı var? :)
Nikola Lošić

1
@ NikolaLošić: Peki, soru JDBC kullanımı hakkında soru soruyor ResultSet, bu yüzden hiç şüphe yok ResultSet. Nitekim, connectionburada neden ihtiyaç duyulduğu açık görünmüyor . JOOQ kullanıyorsanız, yine de etrafınızda oturan bir DSLContext( DSL.using(connection)veya benzeri bir sonuca ) sahip olacaksınız.
Lukas Eder

dahil edilecek doğru JOOQ kitaplığı nedir? Birçoğunu deniyorum ama her biri bana DSL referansında Sınıf bulunamadı hatası veriyor. Thnks
Lorenzo Barbagli

7

@ Jim Cook tarafından yapılan önerilere ek olarak. Başka bir düşünce, if-elses yerine bir anahtar kullanmaktır:

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

4
Geriye doğru döngü yapmak (sıfır dizini karşılaştırmak) da daha hızlıdır (dizini bir ifadeyle karşılaştırmaktan).
Dave Jarvis

4

Bu cevap en etkili cevap olmayabilir ama kesinlikle dinamiktir. Yerel JDBC'yi Google'ın Gson kitaplığıyla eşleştirerek, bir SQL sonucundan JSON akışına kolayca dönüştürebilirim.

Dönüştürücüyü, örnek DB özellikleri dosyasını, SQL tablo oluşturmayı ve bir Gradle derleme dosyasını (kullanılan bağımlılıklar ile) dahil ettim.

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'
}

Sonuçlar

Temel SEÇİM

[
    {
        "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
    }
]

Ara SEÇİM

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

3

İlk sütun adlarını önceden oluşturun, rs.getString(i)yerine ikinci kullanın rs.getString(column_name).

Aşağıdakiler bunun bir uygulamasıdır:

    /*
     * 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;
    }

nesneye nasıl erişirim ve onu kullanırım .... tüm İsim sütununu yazdırmak istiyorum diyelim ... ve nesne CRUD işlemleri için kolayca kullanılabilir mi?
Prathamesh dhanawade

@Prathameshdhanawade Bu yöntem, JDBC ResultSet'i JSON dizisine dönüştürmek içindir. Geliştiriciler genellikle ham JDBC ResultSet kullanmazlar, genellikle bunu Java nesneleri listesine, yani JSON nesnesine dönüştürürler. Dönüş değerinin JSON nesnelerinden oluşan bir dizi olduğunu görüyorsunuz. Bir nesneye kolayca erişebilirsiniz. JSONObject json = resList.get(i);O zaman JSON nesnesini kullanmakta özgürsünüz json.
coderz

Aslında grafik bir görünüm hazırlamak için nesneye ihtiyacım olacak. Bu yüzden nesneyi manipüle edebilmeyi merak ettim. Thnx.
Prathamesh dhanawade

Lütfen "grafik görünümü" açıklar mısınız? Veya bir örnek verilir mi?
coderz

Sütun değerini şu şekilde görüntülemeye çalışıyorum: JSONObject obj = jsonList.get (1); System.out.println (obj.getString ( "isim") + "\ t" + obj.getString ( "şirketi")); ancak "org.json.JSONException: JSONObject [" ad "] bulunamadı" olarak bir hata alınıyor.
Prathamesh dhanawade

2

Herkes planı bu uygulama kullanımı ise Bunu isteyebilirsin bu check out ve bu

Bu, dönüşüm kodunun benim versiyonum:

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

2

Bir uyarı olarak, if / then döngüsü numaralandırma anahtarından daha verimlidir. Ham enum tamsayısına karşı anahtarınız varsa, bu daha etkilidir, ancak değişkene karşı, eğer / o zaman en azından Java 5, 6 ve 7 için daha etkilidir.

Yani, bazı nedenlerden dolayı (bazı performans testlerinden sonra)

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

daha hızlı

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

Birkaç kişinin benden şüphe ettiğini görüyorum, bu yüzden Java 7'den aldığım çıktıyla birlikte farkı görmek için kendiniz çalıştırabileceğiniz kodu buraya göndereceğim. 10 enum değerine sahip aşağıdaki kodun sonuçları aşağıdaki gibidir. Buradaki anahtar, enumun sıralı sabitleriyle karşılaştıran bir tamsayı değerinin if / then kullanılmasıyla, ham sıralı değerlere karşı bir enum sıralı değerine sahip anahtarla, her enum adına karşı enum ile anahtarın kullanılmasıdır. Bir tamsayı değerine sahip if / then, diğer her iki anahtarı da geride bıraktı, ancak son anahtar ilk anahtardan biraz daha hızlıydı, if / else'ten daha hızlı değildi.

/ Else 23 ms sürdüyse
Anahtar 45 ms sürmüştür
Anahtar 2 30 ms sürmüştür
Toplam eşleşmeler: 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);
    }
}

Pekala, tamam ama .. pratik gerçek şu ki, herhangi bir gerçek kullanım durumu için bu kodlama alternatifleri arasındaki fark o kadar küçüktür ki, gerçek bir uygulamada, aralarındaki performans farklılıkları büyük olasılıkla ölçülemeyecek kadar küçük olacaktır. Önce kodunuzu düzeltin ve sonra (ancak o zaman) hızlı hale getirin (daha hızlı olması gerekiyorsa).
scottb

Kabul edildi, ancak asıl soru en hızlı, en verimli yolla ilgiliydi. Kodun okunmasını veya sürdürülmesini zorlaştıran, ancak daha verimli olan birçok stil vardır, ancak bunlar genellikle gelecekte bir noktada derleyici optimizasyonları ile çözülür. Bunun bir örneği intern(), Java'nın çoğu modern sürümünde artık büyük ölçüde ihtiyaç duyulmayan dizelerin kullanılmasıdır .
Marcus

Kabul edildi, ancak eğer-öyleyse ve durum değiştirme blokları, her durumda bakım, sağlamlık ve okunabilirlik sorunları için zayıf çözümlerdir. Sahip olduğunuz (veya kodunu değiştirebileceğiniz) numaralandırmalar için en iyi uygulama, genellikle zengin bir enum türünde sabit özgü yöntemleri kullanmaktır. orada çözümler.
scottb

1

If-else mesh çözümünü tercih edenler için lütfen şunları kullanın:

String columnName = metadata.getColumnName(
String displayName = metadata.getColumnLabel(i);
switch (metadata.getColumnType(i)) {
case Types.ARRAY:
    obj.put(displayName, resultSet.getArray(columnName));
    break;
...

Çünkü sorgunuzda takma ad olması durumunda, sütun adı ve sütun etiketi iki farklı şeydir. Örneğin şunları yürütürseniz:

select col1, col2 as my_alias from table

Alacaksın

[
    { "col1": 1, "col2": 2 }, 
    { "col1": 1, "col2": 2 }
]

Ziyade:

[
    { "col1": 1, "my_alias": 2 }, 
    { "col1": 1, "my_alias": 2 }
]

0
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;
    }

}

Cevabınıza biraz açıklama ekleyin.
Sahil Mittal

0
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;
}

-1

Diğer bir şekilde, burada ArrayList ve Map kullandım, bu yüzden json nesnesini satır satır çağırmak değil, sonuç kümesinin yinelemesi bittikten sonra:

 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);    
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.