2011-06-22 9 views
2

私は大量の行を更新しようとしています(約5M)。私はまず、結果セットに非常に多くの行がフェッチされるというヒープオーバーフロー問題を発見しました。私はこのマシンでヒープサイズを上げたくないので、これを行う有効な方法があるのだろうかと思っていました。JDBCとMySQLを使用した大きなResultsetの更新

私はsetFetchSize(Integer.MIN_VALUE)を設定しようとしたが、私は更新関数を呼び出すときに、私はこのエラーを取得する:

ストリーミング結果は [email protected]がまだアクティブである設定

。ストリーミング結果セットが開いていて、特定の接続で使用されている場合は、ステートメントは発行されません。クエリをさらに試行する前に、アクティブなストリーミング結果セットに.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) 
     ...   
    } 

何ができるかに関するアイデアは?あなたはrs.next()ループ内にupdateRow()メソッドを呼び出し

おかげ

+2

試してみるように閉じることがあります。これが助けてくれることを願う –

+0

これは正解です。 MySQLワイヤプロトコルは、同じ接続上で複数のステートメント実行を同時にサポートしていません。したがって、実際には2つのコマンドが必要な場合は、最初のコマンドの完全な結果を完全に読み取る必要があります(これは「ストリーミングしない」モードです)。または、1つの接続で結果を「ストリーミング」できます。 –

答えて

2

。現在while(rs.next())ループ内で処理されているSQLフィールド(ID)に対してSQLの更新を試みます。これはあなたが得るエラーを発生させます。私はあなたが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

Connectionオブジェクトは、一度に複数のResultSetオブジェクトを保持するべきではありません。 は、ResultSetおよびStatementオブジェクトの作成後、それぞれが明示的にデータベースに更新するための1つの新しい接続を作成して使用するには、 resultSet.close() statement.close()

関連する問題