【问题标题】:Operation not allowed after ResultSet closed errorResultSet 关闭错误后不允许操作
【发布时间】:2012-10-02 20:51:42
【问题描述】:

我有一个代码在处理后将数据插入表中,但我一次又一次收到错误

ResultSet 关闭后不允许操作

这是我的代码。

 try {
        Connection con = null;
        Class.forName("com.mysql.jdbc.Driver");
        con = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/asteriskcdrdb", "root", "techsoft");
        Statement st = con.createStatement();
        ResultSet rs = st.executeQuery("Select * from asteriskcdrdb.sp1");
        while (rs.next()) {
            AreaCode = rs.getString("AreaCode");
            //System.out.println(AreaCode);
            String Pulse = rs.getString("Pulse");
            Rate = rs.getInt("Rate/pulse");
            // System.out.println(Rate);
            if (AreaCode.equals(str)) {
                System.out.println("Hii");
                try {
                    Connection conn = null;
                    Class.forName("com.mysql.jdbc.Driver");
                    conn = DriverManager.getConnection(
                            "jdbc:mysql://localhost:3306/asteriskcdrdb", "root", "techsoft");
                    Statement stmt = conn.createStatement();
                    rst = stmt.executeQuery("Select * from cdr where src ='9035020090'");
                    while (rst.next()) {
                        calldate = rst.getString("calldate");
                        // System.out.println(calldate);
                        clid = rst.getString("clid");
                        src = rst.getString("src");
                        dst = rst.getString("dst");
                        dcontext = rst.getString("dcontext");
                        channel = rst.getString("channel");
                        dstchannel = rst.getString("dstchannel");
                        lastapp = rst.getString("lastapp");
                        lastdata = rst.getString("lastdata");
                        duration = rst.getString("duration");
                        //System.out.println(duration);
                        dur = Integer.parseInt(duration);
                        //System.out.println(dur);
                        data.add(dur);
                        billsec = rst.getString("billsec");
                        disposition = rst.getString("disposition");
                        amaflags = rst.getString("amaflags");
                        accountcode = rst.getString("accountcode");
                        uniqueid = rst.getString("uniqueid");
                        userfield = rst.getString("userfield");
                        int newcost = checktime(dur, Rate);
                        stmt.executeUpdate("insert into cdrcost (
         calldate,clid,src,dst,dcontext,channel,
         dstchannel,lastapp, lastdata,duration,billsec,
         disposition,amaflags,accountcode,uniqueid,
         userfield,cdrcost) values ('" + calldate + "','" + 
         clid + "','" + src + "','" + dst + "','" + dcontext 
         + "','" + channel + "','" + dstchannel + "','" + 
         lastapp + "','" + lastdata + "','" + duration + "','" + 
         billsec + "','" + disposition + "','" + amaflags 
          + "','" + accountcode + "','" + uniqueid + "','" + userfield  
         + "','" + newcost + "')");
                     }

                } catch (Exception e) {
                    System.out.println(e);
                }
            } else if (AreaCode.equals(str2)) {
                System.out.println("Hii2");
            }
        }

    } catch (Exception e) {
        System.out.println(e);
    }
}

public static int checktime(int dur, int Rate) {
    int cost = 0;

    // System.out.println(c);
    int min = 60;

    int quotient = dur / min;
    // System.out.println(quotient);

    int reminder = dur % min;
    //  System.out.println(reminder);

    if (reminder > 0) {
        quotient = quotient + 1;
        // System.out.println(quotient);

        // System.out.println(cost);
    }
    cost = quotient * Rate;
    return cost;
}

【问题讨论】:

    标签: java mysql jdbc resultset


    【解决方案1】:
    stmt.executeUpdate("insert into cdrcost (
             calldate,clid,src,dst,dcontext,channel,
             dstchannel,lastapp, lastdata,duration,billsec,
             disposition,amaflags,accountcode,uniqueid,
             userfield,cdrcost) values ('" + calldate + "','" + 
             clid + "','" + src + "','" + dst + "','" + dcontext 
             + "','" + channel + "','" + dstchannel + "','" + 
             lastapp + "','" + lastdata + "','" + duration + "','" + 
             billsec + "','" + disposition + "','" + amaflags 
              + "','" + accountcode + "','" + uniqueid + "','" + userfield  
             + "','" + newcost + "')");
    

    在这里,当您在while 循环内执行此update 时,前一个select 查询的当前resultset 将关闭。所以你不能在下一次迭代中做res.next()

    如果想在断开连接后hold数据,可以使用Cached Row Set

    ResultSet res = ....
    CachedRowSet rowset = new CachedRowSetImpl();
    rowset.populate(res);
    

    CachedRowSet 是一个无连接的 ResultSet。我没有用太多,因为我没有任何需要。但是,我可以在这里分享一些链接来帮助您理解这些概念

    或者你最好看看RowSetFactory,它为你提供了方法createCachedRowSet(),可以为你创建CachedRowSet实例。

    您可以从RowSetProvider 获取RowSetFactory。然后您可以获取CachedRowSet 并对其进行迭代。

    RowSetFactory factory = RowSetProvider.newFactory();
    CachedRowSet crs = factory.createCachedRowSet();
    crs.populate(res);
    
    while(crs.next()) {
        crs.getString(1);  // Works similar to `ResultSet`
    }
    

    【讨论】:

    • @Rohit Jain .. 谢谢先生您的快速回复..请您指导我如何纠正
    • @LuiggiMendoza。别着急,我等下次再回复。会给你充分的机会:) :P
    • 您可以提出解决方案以便给出更好的答案。此外,OP 应该为所有操作使用相同的连接,无需为第一个ResultSet 中的每个结果打开一个新的Connection
    • @LuiggiMendoza 那么如何纠正这个错误先生。我真的不知道..请帮我先生
    • @RohitJain Sir 在哪里放置 CachedRowSet rowset = new CachedRowSetImpl(); rowset.populate(res);在 while (res.next) 循环内部或外部
    【解决方案2】:

    在给你答案之前,你应该了解一些关于数据库访问和 JDBC 的基本知识:

    • 不得在大型操作中创建许多连接来访问数据库。如果您需要在单个方法中读取、插入、更新或删除数据,则应仅使用 1 个连接。打开连接是一项成本很高的操作。如果您还没有注意到,那是因为您处于单用户(您)环境中。

    • 每个Statement 使用一个或多个 ResultSets。由于您是初学者,因此假设每个Statement 将有一个ResultSet。如果修改了Statement中的数据,则绑定到这个StatementResultSet将被关闭,不能在以后的操作中使用。这就是您遇到问题的原因(如其他答案所述)。

    • 如果您将执行将使用参数的 SQL 语句,请使用 PreparedStatement。否则,您的应用程序将容易受到 SQL 注入攻击(即黑客可能会关闭您的数据库服务器,您和我都知道这是一件坏事)。

    • 您应该在使用资源后关闭它们。这意味着,您应该关闭ResultSets、Statements 和Connection(按此顺序)。

    根据所有这些注释,您的代码将更改为:

    Connection con = null;
    Statement st = null;
    ResultSet rs = null;
    try {
        Class.forName("com.mysql.jdbc.Driver");
        con = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/asteriskcdrdb", "root", "techsoft");
        st = con.createStatement();
        rs = st.executeQuery("Select * from asteriskcdrdb.sp1");
        while (rs.next()) {
            AreaCode = rs.getString("AreaCode");
            String Pulse = rs.getString("Pulse");
            Rate = rs.getInt("Rate/pulse");
            if (AreaCode.equals(str)) {
                Statement stmt = null;
                ResultSet rst = null;
                PreparedStatement insSt = null;
                try {
                    //using the first connection
                    stmt = con.createStatement();
                    rst = stmt.executeQuery("Select * from cdr where src ='9035020090'");
                    while (rst.next()) {
                        calldate = rst.getString("calldate");
                        clid = rst.getString("clid");
                        src = rst.getString("src");
                        dst = rst.getString("dst");
                        dcontext = rst.getString("dcontext");
                        channel = rst.getString("channel");
                        dstchannel = rst.getString("dstchannel");
                        lastapp = rst.getString("lastapp");
                        lastdata = rst.getString("lastdata");
                        duration = rst.getString("duration");
                        dur = Integer.parseInt(duration);
                        data.add(dur);
                        billsec = rst.getString("billsec");
                        disposition = rst.getString("disposition");
                        amaflags = rst.getString("amaflags");
                        accountcode = rst.getString("accountcode");
                        uniqueid = rst.getString("uniqueid");
                        userfield = rst.getString("userfield");
                        int newcost = checktime(dur, Rate);
                        //every ? is a parameter in the query
                        insSt = con.prepareStatement(
                            "insert into cdrcost (calldate,clid,src,dst,dcontext,channel, dstchannel, lastapp, lastdata,duration,billsec, disposition,amaflags,accountcode,uniqueid, userfield,cdrcost) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
                        //setting every parameter
                        insSt.setObject(1, calldate);
                        insSt.setObject(2, clid);
                        insSt.setObject(3, src);
                        insSt.setObject(4, dst);
                        insSt.setObject(5, dcontext);
                        insSt.setObject(6, channel);
                        insSt.setObject(7, dstchannel);
                        insSt.setObject(8, lastapp);
                        insSt.setObject(9, lastdata);
                        insSt.setObject(10, duration);
                        insSt.setObject(11, billsec);
                        insSt.setObject(12, disposition);
                        insSt.setObject(13, amaflags);
                        insSt.setObject(14, accountcode);
                        insSt.setObject(15, uniqueid);
                        insSt.setObject(16, userfield);
                        insSt.setObject(17, newcost);
                        //executing the insert statement
                        insSt.executeUpdate();
                    }
                } catch (Exception e) {
                    System.out.println(e);
                } finally {
                    //closing the resources in this transaction
                    try {
                        //the insSt statement doesn't have a resultset
                        if (insSt != null) {
                            insSt.close();
                        }
                        //the rst ResultSet is bounded to stmt Statement, it must be closed first
                        if (rst != null) {
                            rst.close();
                        }
                        if (stmt != null) {
                            stmt.close();
                        }
                    } catch (SQLException sqle) {}
                }
            } else if (AreaCode.equals(str2)) {
                System.out.println("Hii2");
            }
        }
    } catch (Exception e) {
        System.out.println(e);
    } finally {
        //closing the resources in this transaction
        //similar logic than the used in the last close block code
        try {
            if (rs != null) {
                rs.close();
            }
            if (st != null) {
                st.close();
            }
            //at the last of all the operations, close the connection
            if (con != null) {
                con.close();
            }
        } catch (SQLException sqle) {}
    }
    

    附带说明,您是初学者这一事实并不意味着您应该编写代码只是为了让它工作。您应该始终遵循最佳做法。 IMO 最好在这些情况下寻求指导。

    【讨论】:

    • @Ram 如果答案适用于您的情况,请将其标记为答案(单击我的答案旁边的检查)。
    【解决方案3】:

    在给定的时间点,一个连接只能被一个语句使用。执行语句的结果集共享相同的连接。因此,如果您想在从结果集中读取每一行时对其执行更新,您应该在创建语句时请求 UPDATEABLE 结果集,然后在浏览结果集时更新当前行中的列。

    由于您似乎需要将记录插入到不同的表中,您可以执行以下操作之一:

    1. 使用缓存行集

      1. 将您的结果集放入CachedRowSet
      2. 关闭结果集和语句。
      3. 遍历缓存的行集,为每个插入创建一个语句并执行它。
    2. 使用单独的对象来跟踪需要插入的内容

      1. 将要插入的记录作为对象构建到列表中。
      2. 完成结果集后,关闭它,关闭语句。
      3. 为 INSERT 语句准备一条新语句,即 PreparedStatement。
      4. 批量插入记录。
    3. 最坏情况,使用三个连接,一个用于外部查询,一个用于内部查询,一个用于插入

    以下代码(完全不是生产质量,只是上面第三个选项的肮脏实现):

        try
        {
            // used for outer query.
            Connection outerCon = null;
            // used for inner query.
            Connection innerCon = null;
            // used to insert records.
            Connection insCon = null;
            Class.forName("com.mysql.jdbc.Driver");
            outerCon = DriverManager.getConnection("jdbc:mysql://localhost:3306/asteriskcdrdb", "root", "techsoft");
            innerCon = DriverManager.getConnection("jdbc:mysql://localhost:3306/asteriskcdrdb", "root", "techsoft");
            insCon = DriverManager.getConnection("jdbc:mysql://localhost:3306/asteriskcdrdb", "root", "techsoft");
            Statement st = outerCon.createStatement();
            ResultSet rs = st.executeQuery("Select * from asteriskcdrdb.sp1");
            while (rs.next())
            {
                AreaCode = rs.getString("AreaCode");
                // System.out.println(AreaCode);
                String Pulse = rs.getString("Pulse");
                Rate = rs.getInt("Rate/pulse");
                // System.out.println(Rate);
                if (AreaCode.equals(str))
                {
                    System.out.println("Hii");
                    try
                    {
                        Statement stmt = innerCon.createStatement();
                        ResultSet rst = stmt.executeQuery("Select * from cdr where src ='9035020090'");
                        while (rst.next())
                        {
                            calldate = rst.getString("calldate");
                            // System.out.println(calldate);
                            clid = rst.getString("clid");
                            src = rst.getString("src");
                            dst = rst.getString("dst");
                            dcontext = rst.getString("dcontext");
                            channel = rst.getString("channel");
                            dstchannel = rst.getString("dstchannel");
                            lastapp = rst.getString("lastapp");
                            lastdata = rst.getString("lastdata");
                            duration = rst.getString("duration");
                            // System.out.println(duration);
                            dur = Integer.parseInt(duration);
                            // System.out.println(dur);
                            data.add(dur);
                            billsec = rst.getString("billsec");
                            disposition = rst.getString("disposition");
                            amaflags = rst.getString("amaflags");
                            accountcode = rst.getString("accountcode");
                            uniqueid = rst.getString("uniqueid");
                            userfield = rst.getString("userfield");
                            int newcost = checktime(dur, Rate);
                            Statement insStmt = insCon.createStatement();
                            stmt
                                .executeUpdate("insert into cdrcost (calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp, lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield,cdrcost) values ('"
                                    + calldate
                                    + "','"
                                    + clid
                                    + "','"
                                    + src
                                    + "','"
                                    + dst
                                    + "','"
                                    + dcontext
                                    + "','"
                                    + channel
                                    + "','"
                                    + dstchannel
                                    + "','"
                                    + lastapp
                                    + "','"
                                    + lastdata
                                    + "','"
                                    + duration
                                    + "','"
                                    + billsec
                                    + "','"
                                    + disposition
                                    + "','"
                                    + amaflags
                                    + "','"
                                    + accountcode + "','" + uniqueid + "','" + userfield + "','" + newcost + "')");
                            insStmt.close();
                        }
                        rst.close();
                        stmt.close();
    
                    }
                    catch (Exception e)
                    {
                        System.out.println(e);
                    }
                }
                else if (AreaCode.equals(str2))
                {
                    System.out.println("Hii2");
                }
            }
            rs.close();
            st.close();
    
        }
        catch (Exception e)
        {
            System.out.println(e);
        }
    

    【讨论】:

    • 如响应中所建议的,您可以使用这两种方法之一。你在寻找什么具体的东西吗?
    • 先生,我对编程领域很陌生,真的从来没有用过这个......所以请帮我写代码......请先生
    • 请查看有关第三个选项的更新以及对代码的修改以实现该选项。
    猜你喜欢
    • 2012-06-11
    • 1970-01-01
    • 2017-04-17
    • 2018-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多