web-dev-qa-db-ja.com

Java.sql.SQLExceptionの取得:ResultSetを閉じた後は操作は許可されません

次のコードを実行すると、例外が発生します。私は彼が同じ接続オブジェクトで新しいステートメントを準備しているからだと思います。準備済みステートメントを作成し、rs2を使用できるように、これをどのように書き直す必要がありますか?同じDBへの接続であっても、新しい接続オブジェクトを作成する必要がありますか?

    try 
    {
        //Get some stuff
        String name = "";
        String sql = "SELECT `name` FROM `user` WHERE `id` = " + userId + " LIMIT 1;";
        ResultSet rs = statement.executeQuery(sql);
        if(rs.next())
        {
            name = rs.getString("name");
        }

        String sql2 = "SELECT `id` FROM  `profiles` WHERE `id` =" + profId + ";";
        ResultSet rs2 = statement.executeQuery(sql2);
        String updateSql = "INSERT INTO `blah`............"; 
        PreparedStatement pst = (PreparedStatement)connection.prepareStatement(updateSql);    

        while(rs2.next()) 
        { 
            int id = rs2.getInt("id");
            int stuff = getStuff(id);

            pst.setInt(1, stuff);
            pst.addBatch();

        }

        pst.executeBatch();

    } 
    catch (Exception e) 
    {
        e.printStackTrace();
    }

private int getStuff(int id)
{

    try
    {   

            String sql = "SELECT ......;";
            ResultSet rs = statement.executeQuery(sql);

            if(rs.next())
            {
                return rs.getInt("something");

            }
            return -1;
    }//code continues
19
samxli

問題は、getStuff()でデータを取得する方法にあります。 getStuff()にアクセスするたびに、新しいResultSetを取得しますが、閉じません。

これはStatementクラスの期待に違反します(ここを参照- http://docs.Oracle.com/javase/7/docs/api/Java/sql/Statement.html ) :

デフォルトでは、Statementオブジェクトごとに同時に開くことができるResultSetオブジェクトは1つだけです。したがって、1つのResultSetオブジェクトの読み取りが別のResultSetオブジェクトの読み取りとインターリーブされる場合、それぞれが異なるStatementオブジェクトによって生成されている必要があります。 Statementインターフェイスのすべての実行メソッドは、ステートメントの現在のResultSetオブジェクトが存在する場合、それを暗黙的に閉じます。

事態をさらに悪化させるのは、呼び出し元コードからのrsです。また、statementフィールドから派生していますが、閉じられていません。

一番下の行:同じResultSetオブジェクトに関連するいくつかのStatementが同時に開かれています。

28
Itay Maman

ResultSetオブジェクトは、それを生成したStatementオブジェクトが閉じられるか、再実行されるか、または複数の結果のシーケンスから次の結果を取得するために使用されると、自動的に閉じられます。

while(rs2.next())の後、rs1から何かにアクセスしようとしていると思います。しかし、rs2を取得するためにステートメントを再実行したため、すでに閉じられています。あなたはそれを閉じなかったので、私はそれが以下で再び使用されると信じています。

9