2011-06-22 49 views
2

我正在嘗試更新一大組行(大約5M)。我首先遇到了在結果集中獲取太多行的堆溢出問題。由於我不想在這臺機器上提高堆大小,所以我想知道是否有這樣做的有效方法。使用JDBC和MySQL更新大型結果集

我嘗試設置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) 
     ...   
    } 

任何想法可以做什麼?

感謝

+2

嘗試創建一個新的連接,並使用一個更新到數據庫中。希望這會有所幫助。 –

+0

這是正確的答案。 MySQL有線協議不支持在同一連接上同時執行多個語句。所以如果真的需要2條命令,第一條命令的全部結果必須完全讀取(這是「非流式傳輸」模式),或者可以通過一個連接「流」結果,並通過第二條命令進行更新。 –

回答

2

你調用updateRow()的rs.next()內循環的方法;它試圖對當前在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對象後,每個人都有收明確像, resultSet.close() 將statement.close()