1

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

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

3 回答 3

3

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

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

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

  • 如果您将执行将使用参数的 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 最好在这些情况下寻求指导。

于 2012-10-12T05:22:14.783 回答
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内执行此操作时,前一个查询的当前将关闭。所以你不能在下一次迭代中做。whileresultsetselectres.next()

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

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

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

或者您可以更好地查看RowSetFactory,它为您提供createCachedRowSet()了可以为您创建CachedRowSet实例的方法。

您可以RowSetFactoryRowSetProvider获取。然后你可以获取CachedRowSet并迭代它。

RowSetFactory factory = RowSetProvider.newFactory();
CachedRowSet crs = factory.createCachedRowSet();
crs.populate(res);

while(crs.next()) {
    crs.getString(1);  // Works similar to `ResultSet`
}
于 2012-10-12T04:36:18.207 回答
0

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

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

  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-10-12T04:38:16.197 回答