ResultSet关闭错误后不允许操作

时间:2012-10-12 04:30:43

标签: java mysql jdbc resultset

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

  

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;
}

3 个答案:

答案 0 :(得分:3)

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

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

  • 每个Statement使用一个或更多 ResultSet。由于您是初学者,因此假设每个Statement都有一个ResultSet。如果您修改Statement中的数据,那么与此ResultSet绑定的Statement将被关闭,并且无法在将来的操作中使用。这就是你遇到问题的原因(如其他答案所述)。

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

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

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

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最好在这些情况下寻求指导。

答案 1 :(得分: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 + "')");

此处,当您在update循环中执行此while时,之前resultset查询的当前select将被关闭。所以你不能在下一次迭代中做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`
}

答案 2 :(得分:0)

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

由于您似乎需要将记录插入到其他表中,因此可以执行以下操作之一:

  1. 使用缓存的行集

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

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

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

        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);
        }