Обновление большого Resultset с JDBC и MySQL - PullRequest
3 голосов
/ 22 июня 2011

Я пытаюсь обновить большой набор строк (около 5M). Сначала я столкнулся с проблемой переполнения кучи, когда в результирующем наборе было выбрано так много строк. Поскольку я не хочу увеличивать размер кучи на этой машине, мне было интересно, есть ли эффективный способ сделать это.

Я попытался установить setFetchSize(Integer.MIN_VALUE), но затем, когда я вызываю функцию обновления, я получаю эту ошибку:

Набор результатов потоковой передачи com.mysql.jdbc.RowDataDynamic@2087c268 все еще активен. Никакие операторы не могут быть выданы, когда какие-либо потоковые наборы результатов открыты и используются для данного соединения. Убедитесь, что вы вызвали .close() для всех активных наборов результатов потоковой передачи, прежде чем пытаться выполнить больше запросов.

Если я вызову close() в наборе результатов, я, конечно, не смогу его обновить. Вот мой код

public void getRows()
    {
         Statement stmt = null;
         ResultSet rs = null;
         int countSpecialChars = 0;
         int upper = 0, lower = 0, digits =0;
         String pass = null;
         int id = 0;

         char thisChar;
         String query = "select id,pass from datatable";
            try {
              this.conn.setAutoCommit(false);
              stmt = this.conn.createStatement();
              stmt.setFetchSize(Integer.MIN_VALUE);
              rs = stmt.executeQuery(query);

          while (rs.next()) {
                   pass = rs.getString(2).trim();
                   id = rs.getInt(1);
            for (int i=0; i<=pass.length()-1; i++)
             {
                thisChar= pass.charAt(i);
                    if (thisChar >= 65 && thisChar <= 90) {
                    upper++; 
                } else if (thisChar >= 97 && thisChar <= 122) {
                    lower++;
                }  else if( thisChar >= 48 && thisChar <= 57) {
                    digits++;
                }
                else
                {countSpecialChars++;}
             }
                Entropy entropy = new Entropy();
                double naiveEntropy = entropy.naiveEntropy(pass);
             NumberFormat formatter = new DecimalFormat("#0.00");
             this.updateRow(id, pass.length(), digits, upper, lower, countSpecialChars, Double.parseDouble(formatter.format(naiveEntropy)));
             countSpecialChars = 0;
             upper=digits=0;
             lower = 0;
          }
            rs.close();
        }
        catch (SQLException e)
        ...
    }

    public void updateRow(int id, int length, int numbers, int upper, 
            int lower, int specialChars, double naiveEntropy )
    {
        PreparedStatement updatePassEntry = null;

        String updateString = "update cwlCompatiblePassUnique " +
        "set length = ?, numbers = ?, upper = ?, lower = ?, specialChars = ?, ShannonEntropy = ?  where id = ?";
        try {
             this.conn.setAutoCommit(false);
             updatePassEntry = this.conn.prepareStatement(updateString);
             updatePassEntry.setInt(1, length);
             ...
             updatePassEntry.setInt(7, id);
             updatePassEntry.executeUpdate();
             this.conn.commit();
         }
        catch (SQLException e)
        ...         
    }

Есть идеи, что можно сделать?

Спасибо

Ответы [ 2 ]

2 голосов
/ 22 июня 2011

вы вызываете метод updateRow () внутри цикла rs.next (); который пытается обновить SQL для поля SQL (id), которое в данный момент обрабатывается внутри вашего цикла while (rs.next ()) это поднимет ошибку, которую вы получите. я предлагаю вам написать метод для извлечения rs и сохранения их в векторе объектов Java в качестве первого шага. этот метод закроет rs после выхода. затем напишите другой метод для обработки и обновления данных в ваших кэшированных векторных объектах. как то так:

    private void Vector<DataSet> getDataSet(){
    Vector<DataSet> data=new Vector<DataSet>();
     String query = "select id,pass from datatable";
                try {
                  this.conn.setAutoCommit(false);
                  stmt = this.conn.createStatement();
                  stmt.setFetchSize(Integer.MIN_VALUE);
                  rs = stmt.executeQuery(query);

                   while (rs.next()) {
                       pass = rs.getString(2).trim();
                       id = rs.getInt(1);
                       data.addElement(new DataSet(id,pass));
                     }

                }catch(Exception e){

    // here close connection and rs
    }
}
    private void udpateData(Vector<dataSet> data){
    //process data and update her
    }

    static class DataSet{
    int id;
    String pass;
    //constructor here
    }
0 голосов
/ 30 мая 2013

Объект подключения не должен содержать несколько объектов набора результатов одновременно. После создания объектов ResultSet и Statement все объекты должны быть явно закрыты, как, resultSet.close () statement.close ()

...