2013-06-02 5 views
9

Можно ли получить целую строку без вызова getInt (..) getString (..) для каждого столбца?Извлечь всю строку с ResultSet

У меня есть несколько потоков, каждый протектор должен написать результат в какую-нибудь поточную безопасную коллекцию.
Я хочу, чтобы иметь возможность писать строки непосредственно в эту коллекцию, а после этого анализировать элементы этой коллекции и извлекать значения на основе типов столбцов.

+2

Нет. Вам нужно разобрать строку в «Объекты» и сохранить их в «Коллекция». Рассмотрим _querying_ данные в кусках в потоках. –

+1

Если вы не хотите писать такой код, посмотрите, например. Весенний шаблон JDBC. Это облегчает вам множество таких кодовых табличек кодов без нагрузки ORM. –

+0

Вы хотите ORM. http://stackoverflow.com/questions/tagged/java+orm?sort=frequent&pagesize=50 или google для java orm –

ответ

1

Ниже приведен пример использования запроса для определения размера запроса и последующего разделения обработки на несколько потоков.

Я использую MySQL, поэтому для этого написаны запросы. Вам нужно будет изменить запросы для вашего механизма базы данных.

public static void main(String[] args) throws Exception { 
    final int count; 
    try (final Connection conn = DATA_SOURCE.getConnection()) { 
     final String countQuery = "SELECT COUNT(*) FROM my_table"; 
     try (final PreparedStatement ps = conn.prepareStatement(countQuery); 
       final ResultSet resultSet = ps.executeQuery()) { 
      resultSet.next(); 
      count = resultSet.getInt(1); 
     } 
    } 
    final int chunksize = 1000; 
    final Queue<SqlResult> results = new ConcurrentLinkedQueue<>(); 
    final ExecutorService es = Executors.newFixedThreadPool(10); 
    for (int end = 0; end < count; end += chunksize) { 
     es.execute(new ResultReader(count, end, DATA_SOURCE, results)); 
    } 
} 

private static class ResultReader implements Runnable { 

    private final int start; 
    private final int size; 
    private final DataSource dataSource; 
    private final Queue<SqlResult> results; 

    public ResultReader(int start, int size, DataSource dataSource, Queue<SqlResult> results) { 
     this.start = start; 
     this.size = size; 
     this.dataSource = dataSource; 
     this.results = results; 
    } 

    @Override 
    public void run() { 
     try (final Connection connection = dataSource.getConnection()) { 
      final String query = "SELECT id, something, somethingElse FROM my_table LIMIT ?, ?"; 
      try (final PreparedStatement ps = connection.prepareStatement(query)) { 
       ps.setInt(1, start); 
       ps.setInt(2, size); 
       try (final ResultSet rs = ps.executeQuery()) { 
        while (rs.next()) { 
         final SqlResult sqlResult = new SqlResult(); 
         sqlResult.setId(rs.getInt("id")); 
         sqlResult.setSomething(rs.getString("something")); 
         sqlResult.setSomethingElse(rs.getString("somethingElse")); 
         results.add(sqlResult); 
        } 
       } 
      } 
     } catch (SQLException ex) { 
      Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
} 

private static class SqlResult { 

    private int id; 
    private String something; 
    private String somethingElse; 

    public int getId() { 
     return id; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

    public String getSomething() { 
     return something; 
    } 

    public void setSomething(String something) { 
     this.something = something; 
    } 

    public String getSomethingElse() { 
     return somethingElse; 
    } 

    public void setSomethingElse(String somethingElse) { 
     this.somethingElse = somethingElse; 
    } 
} 

Это предполагает, что у вас уже есть пул соединений, используя DataSource.

Каждый из рабочих выполняет запрос с использованием LIMIT и обрабатывает результаты в SqlResult объектах и ​​добавляет их к одновременному Queue.

+0

Не 'LIMIT?,?' MySQL зарезервированный ключ? AFAIK не будет работать на Oracle и SQL Server. –

+0

@LuiggiMendoza справедливой точки. Я не знаю, как это сделать. Я поправлю свой ответ, чтобы упомянуть, что он специфичен для MySQL. –

+0

спасибо, но моя «проблема» с resultSet.getInt (1) Я хотел этого избежать. – yuris

4

Вы можете создать класс, как этот, который отображает SQL типы данных с типами Java данных:

class Row 
{ 
    public Map <Object,Class> row; 
    public static Map <String, Class> TYPE; 

    static 
    { 
     TYPE = new HashMap<String, Class>(); 

     TYPE.put("INTEGER", Integer.class); 
     TYPE.put("TINYINT", Byte.class); 
     TYPE.put("SMALLINT", Short.class); 
     TYPE.put("BIGINT", Long.class); 
     TYPE.put("REAL", Float.class); 
     TYPE.put("FLOAT", Double.class); 
     TYPE.put("DOUBLE", Double.class); 
     TYPE.put("DECIMAL", BigDecimal.class); 
     TYPE.put("NUMERIC", BigDecimal.class); 
     TYPE.put("BOOLEAN", Boolean.class); 
     TYPE.put("CHAR", String.class); 
     TYPE.put("VARCHAR", String.class); 
     TYPE.put("LONGVARCHAR", String.class); 
     TYPE.put("DATE", Date.class); 
     TYPE.put("TIME", Time.class); 
     TYPE.put("TIMESTAMP", Timestamp.class); 
     // ... 
    } 

    public Row() 
    { 
     row = new HashMap<Object,Class>(); 
    } 

    public void add<t> (t data) 
    { 
     row.put(data, data.getClass()); 
    } 

    public void add (Object data, String sqlType) 
    { 
     add((Row.TYPE.get(sqlType)) data); 
    } 

    public static void formTable (ResultSet rs, ArrayList<Row> table) 
    { 
     if (rs == null) return; 

     ResultSetMetaData rsmd = rs.getMetaData(); 

     int NumOfCol = rsmd.getColumnCount(); 

     while (rs.next()) 
     { 
      row = new Row(); 

      for(int i = 1; i <= NumOfCol; i++) 
      { 
       row.add(rs.getObject(i), rsmd.getColumnTypeName(i)); 
      } 

      table.add(row); 
     } 
    } 
} 

Что вы можете использовать его как это:

List<Row> table = new ArrayList<Row>(); 

Row row = null; 

ResultSet rs = st.executeQuery("SELECT * FROM table_name"); 

Row.formTable(rs, table); 

Тогда вы можете получить поля и направить их в соответствующие типы данных:

for (Row row : table) 
{ 

    for (Object data : row.row.getKeySet()) 
    { 
     System.out.print(" > " + ((row.row.get(data) data)); 
    } 

    System.out.println(); 

} 
+0

Спасибо, хороший кусок кода. Один комментарий: я думаю, что одна строка не должна быть представлена ​​как Карта, а как Список, потому что столбцы упорядочены в таблице. Таким образом, я бы изменил строку строки следующим образом: public List > row; Здесь недостаточно места, поэтому я вставил свой код в новую запись ниже. – ady

2

Строка представлена ​​в виде списка:

import java.math.BigDecimal; 
import java.sql.Date; 
import java.sql.ResultSet; 
import java.sql.ResultSetMetaData; 
import java.sql.SQLException; 
import java.sql.Time; 
import java.sql.Timestamp; 
import java.util.AbstractMap; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.Map.Entry; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

/** 
* @author Adam Dziedzic 
* 
*/ 
public class Row { 
    public List<Entry<Object, Class>> row; 
    public static Map<String, Class> TYPE; 

    static { 
     TYPE = new HashMap<String, Class>(); 

     TYPE.put("INTEGER", Integer.class); 
     TYPE.put("TINYINT", Byte.class); 
     TYPE.put("SMALLINT", Short.class); 
     TYPE.put("BIGINT", Long.class); 
     TYPE.put("REAL", Float.class); 
     TYPE.put("FLOAT", Double.class); 
     TYPE.put("DOUBLE", Double.class); 
     TYPE.put("DECIMAL", BigDecimal.class); 
     TYPE.put("NUMERIC", BigDecimal.class); 
     TYPE.put("BOOLEAN", Boolean.class); 
     TYPE.put("CHAR", String.class); 
     TYPE.put("VARCHAR", String.class); 
     TYPE.put("LONGVARCHAR", String.class); 
     TYPE.put("DATE", Date.class); 
     TYPE.put("TIME", Time.class); 
     TYPE.put("TIMESTAMP", Timestamp.class); 
     TYPE.put("SERIAL",Integer.class); 
     // ... 
    } 

    public Row() { 
     row = new ArrayList<Entry<Object, Class>>(); 
    } 

    public <T> void add(T data) { 
     row.add(new AbstractMap.SimpleImmutableEntry<Object,Class>(data, data.getClass())); 
    } 

    public void add(Object data, String sqlType) { 
     Class castType = Row.TYPE.get(sqlType.toUpperCase()); 
     try { 
      this.add(castType.cast(data)); 
     } catch (NullPointerException e) { 
      e.printStackTrace(); 
      Logger lgr = Logger.getLogger(Row.class.getName()); 
      lgr.log(Level.SEVERE, e.getMessage()+" Add the type "+sqlType+" to the TYPE hash map in the Row class.", e); 
      throw e; 
     } 
    } 

    public static void formTable(ResultSet rs, List<Row> table) 
      throws SQLException { 
     if (rs == null) 
      return; 

     ResultSetMetaData rsmd; 
     try { 
      rsmd = rs.getMetaData(); 

      int NumOfCol = rsmd.getColumnCount(); 

      while (rs.next()) { 
       Row current_row = new Row(); 

       for (int i = 1; i <= NumOfCol; i++) { 
        current_row.add(rs.getObject(i), rsmd.getColumnTypeName(i)); 
       } 

       table.add(current_row); 
      } 
     } catch (SQLException e) { 
      throw e; 
     } 
    } 
} 

Использование:

List<Row> table = new ArrayList<Row>(); 

ResultSet rs = st.executeQuery("SELECT * FROM table_name"); 

Row.formTable(rs, table); 

for (Row row : table) 
{ 
    for (Entry<Object, Class> col: row.row) 
    { 
     System.out.print(" > " + ((col.getValue()).cast(col.getKey()))); 
    } 
    System.out.println(); 
} 
0

Я использовал adam.cajf ответ, очень полезно, однако, мне нужно добавить одну строку кода, чтобы добавить функцию, в противном случае он бросает ошибку в моей конкретной информации задавать.

if (data != null) { 
+1

Вы можете улучшить свой ответ, добавив соответствующий код для ответного ответа или просто напишите отзыв как комментарий к самому ответу. –

Смежные вопросы