これを重複としてマークする前に読んでください。私はグーグルとSOから多くを検索しましたが、探している正確な答えを見つけることができませんでした。
私の質問: JDBCでは、単一のStatement
オブジェクトを使用してexecuteQuery("")
を複数回呼び出すことはできますか?安全ですか? ORクエリごとにステートメントオブジェクトを閉じ、別のクエリを実行するための新しいオブジェクトを作成する必要があります。
例えば:
Connection con;
Statement s;
ResultSet rs;
ResultSet rs2;
try
{
con = getConnection();
s = con.prepareStatement();
try
{
rs = s.executeQuery(".......................");
// process the result set rs
}
finally
{
close(rs);
}
// I know what to do to rs here
// But I am asking, should I close the Statement s here? Or can I use it again for the next query?
try
{
rs2 = s.executeQuery(".......................");
// process the result set rs2
}
finally
{
close(rs2);
}
}
finally
{
close(s);
close(con);
}
はい、Statement
(特にPreparedStatement
)を再利用できます。一般的にはJDBCで再利用する必要があります。ステートメントを再利用せずに、すぐに別の同一のStatement
オブジェクトを作成した場合、非効率的で不適切なスタイルになります。閉じている限り、このスニペットにいるように、finallyブロックで閉じるのが適切です。
あなたが求めているものの例については、このリンクをチェックしてください: jOOq Docs
なぜあなたが尋ねているのか分かりません。 APIの設計とドキュメントは、複数のStatement
、execute
、およびexecuteUpdate
の呼び出しにexecuteQuery
オブジェクトを再利用することはまったく問題ないことを示しています。許可されない場合は、Java docに明示的に文書化されます(APIが異なる可能性が高い)。
さらに、 Statement
のapidocは次のように述べています。
Statement
インターフェースのすべての実行メソッドは、ステートメントの[sic]現在のResultSet
オブジェクトを暗黙的に閉じます。
これは、複数回使用できることを示しています。
TL; DR:はい、以前に開いたexecute
が閉じられることがわかっている限り、単一のStatement
オブジェクトでResultSet
を複数回呼び出すことができます。
あなたの例ではPreparedStatement
を誤って使用しているため、 execute...
メソッドはString
でPreparedStatement
を受け入れます:
SQLException
-[...]メソッドがPreparedStatement
またはCallableStatement
で呼び出される場合
しかし、PreparedStatement
にも答えるには:PreparedStatement
の目的は、パラメータープレースホルダーを使用してステートメントをプリコンパイルし、異なるパラメーター値で複数の実行に再利用することです。
API docs には、特定のPreparedStatement
インスタンスでexecuteQuery()
を複数回呼び出さないことを示すものは何も見つかりません。
ただし、コードはPreparedStatement
を閉じません。その場合、executeQuery()
への呼び出しはSQLException
をスローしますが、executeQuery()
によって返されるResultSet
はスローします。 ResultSetは、PreparedStatement
を再実行すると 自動的に閉じられます です。状況に応じて、不要になったら閉じてください。私はそれを閉じないだろう、私はそうしないことは悪いスタイルだと思うので。
[〜#〜] update [〜#〜]うーん、2つの間のコメントを逃しましたブロックを試してください。この時点でPreparedStatementを閉じた場合、SQLExceptionを取得せずにexecuteQuery()を再度呼び出すことはできません。
Prepared Statement
は、クエリを記憶し、そのクエリで実行するパラメータ化された変数を受け入れる準備ができるようにデータベースに指示します。ストアドプロシージャによく似ています。
Prepared Statement
は2つの主なことを実現します。
クエリ変数を自動的にエスケープして、SQLインジェクションから保護します。
クエリを記憶し、変数を取る準備ができるようにデータベースに指示します。
番号2は、データベースがクエリを1回解釈するだけで済み、手順を実行できる状態になるため、重要です。したがって、パフォーマンスが向上します。
実行呼び出しの間に準備済みステートメントやデータベース接続を閉じないでください。これは信じられないほど非効率的で、プロシージャを作成して記憶するように毎回データベースに指示するため、単純な古いStatement
を使用するよりもオーバーヘッドが大きくなります。データベースが「ホットスポット」用に設定されていて、PreparedStatement
を閉じてもクエリを覚えている場合でも、ネットワークのオーバーヘッドと短い処理時間が発生します。
要するに、Connection
とPreparedStatement
は、完了するまで開いたままにしてください。
編集:実行からResultSet
を返さないことについてコメントするには、これで問題ありません。 executeQuery
は、実行されたクエリに対してResultSet
を返します。
まず、私はあなたのコードについて混乱しています
s = con.prepareStatement();
Java APIにそのような関数が見つかりません。少なくとも1つのパラメーターが必要です。この関数を呼び出したい場合があります。
s = con.createStatement();
2つの操作の間に閉じずに、1つの単一のStatementインスタンスでDB2に2回アクセスするコードを実行しましたが、うまくいきます。
String sql = "";
String sql2 = "";
String driver = "com.ibm.db2.jcc.DB2Driver";
String url = "jdbc:db2://ip:port/DBNAME";
String user = "user";
String password = "password";
Class.forName(driver).newInstance();
Connection conn = DriverManager.getConnection(url, user, password);
Statement statement = conn.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
int count = 0;
while (resultSet.next()) {
count++;
}
System.out.println("Result row count of query number one is: " + count);
count = 0;
resultSet = statement.executeQuery(sql2);
while (resultSet.next()) {
count++;
}
System.out.println("Result row count of query number two is: " + count);