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 つのメソッドでデータの読み取り、挿入、更新、または削除が必要な場合は、1 つの接続のみを使用する必要があります。接続を開くのは、コストのかかる操作です。まだ気付いていない場合は、シングル ユーザー (あなた) の環境にいるためです。

  • EveryStatementは 1つ以上 ResultSetの を使用します。あなたは初心者なので、それぞれStatementに 1 つのResultSet. 内のデータを変更すると、これへStatementResultSet境界Statementが閉じられ、今後の操作で使用できなくなります。それが問題を抱えている理由です(他の回答で述べたように)。

  • パラメータを使用する SQL ステートメントを実行する場合は、PreparedStatement. そうしないと、アプリケーションが SQL インジェクション攻撃を受けやすくなります (つまり、ハッカーがデータベース サーバーをシャットダウンする可能性があります。これはよくないことです)。

  • 使用後はリソースを閉じる必要があります。ResultSetつまり、 s、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

RowSetProviderRowSetFactoryから取得できます。次に、それを取得して反復できます。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 つのステートメントでのみ使用できます。ステートメントの実行結果である結果セットは、同じ接続を共有します。そのため、結果セットから読み取り中に各行の更新を実行する場合は、ステートメントの作成中に UPDATEABLE 結果セットを要求し、結果セットをブラウズしながら現在の行の列をその場で更新する必要があります。

別のテーブルにレコードを挿入する必要があるように見えるので、次のいずれかを実行できます。

  1. キャッシュされた行セットを使用する

    1. 結果セットを に取得しますCachedRowSet
    2. 結果セットとステートメントを閉じます。
    3. キャッシュされた行セットを反復処理し、挿入ごとにステートメントを作成して実行します。
  2. 個別のオブジェクトを使用して、挿入する必要があるものを追跡します

    1. 挿入されるレコードをオブジェクトとしてリストに構築します。
    2. 結果セットの処理が完了したら、それを閉じ、ステートメントを閉じます。
    3. INSERT ステートメント用の新しいステートメント、つまり PreparedStatement を準備します。
    4. レコードをバッチとして挿入します。
  3. 最悪の場合、外部クエリ用、内部クエリ用、挿入用の 3 つの接続を使用します。

次のコード (実稼働品質ではありませんが、上記の 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 に答える