【问题标题】:Updating a large Resultset with JDBC and MySQL使用 JDBC 和 MySQL 更新大型结果集
【发布时间】:2011-09-20 02:17:09
【问题描述】:

我正在尝试更新一大组行(大约 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)
        ...         
    }

关于可以做什么的任何想法?

谢谢

【问题讨论】:

  • 尝试创建一个新连接并使用该连接更新到数据库。希望这会有所帮助。
  • 这是正确答案。 MySQL 有线协议不支持同时在同一个连接上执行多个语句。因此,如果确实需要 2 个命令,则必须完全读取第一个命令的完整结果(这是“非流式传输”模式),或者您可以使用一个连接“流式传输”结果,并通过第二个连接进行更新。

标签: java database jdbc resultset


【解决方案1】:

您在 rs.next() 循环中调用 updateRow() 方法;它尝试对当前正在您的 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
    }

【讨论】:

    【解决方案2】:

    Connection 对象不应一次保存多个结果集对象。 创建 ResultSet 和 Statement 对象后,每个对象都必须像这样显式关闭, 结果集.close() 语句.close()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-09
      • 1970-01-01
      • 2018-05-19
      • 2016-04-30
      • 2019-08-26
      • 1970-01-01
      • 2013-06-18
      • 2012-01-24
      相关资源
      最近更新 更多