TomcatでWebアプリケーションを実行しています。すべてのDBクエリを処理するクラスがあります。このクラスには、Connection
オブジェクトとクエリ結果を返すメソッドが含まれます。
これは接続オブジェクトです。
private static Connection conn = null;
インスタンスは1つ(シングルトン)のみです。
さらに、db内のユーザーの検索など、クエリを実行するメソッドがあります。
public static ResultSet searchUser(String user, String pass) throws SQLException
このメソッドは、静的Connection
オブジェクトを使用します。私の質問は、静的Connection
オブジェクトスレッドセーフでの使用ですか?または、多くのユーザーがsearchUser
メソッドを呼び出すときに問題が発生する可能性がありますか?
静的Connectionオブジェクトスレッドセーフでの使用は安全ですか?
この方法では、すべてのユーザーが送信するすべてのリクエスト間で接続が共有されるため、すべてのクエリが互いに干渉します。ただし、スレッドセーフが唯一の問題ではなく、リソースリークも他の問題です。アプリケーションの存続期間中、1つの接続を開いたままにします。平均的なデータベースは、DBの構成に応じて、通常30分から8時間の間、長時間開いている接続を再利用します。そのため、Webアプリケーションがそれより長く実行されると、接続が失われ、クエリを実行できなくなります。
この問題は、それらのリソースが複数回再利用されるクラスインスタンスのstatic
インスタンス変数として保持されている場合にも適用されます。
常に接続、ステートメント、および結果セットを取得して閉じます可能な限り短いスコープ、できればまったく同じ try-with-resources
ブロック内 次のJDBCイディオムに従ってクエリを実行する場所として:
public User find(String username, String password) throws SQLException {
User user = null;
try (
Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT id, username, email FROM user WHERE username=? AND password=md5(?)");
) {
statement.setString(1, username);
statement.setString(2, password);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
user = new User();
user.setId(resultSet.getLong("id"));
user.setUsername(resultSet.getString("username"));
user.setEmail(resultSet.getString("email"));
}
}
}
return user;
}
ここでResultSet
をnotで返す必要があることに注意してください。 ResultSet
を安全に閉じることができるように、すぐにそれを読み取り、非JDBCクラスにマップしてから返す必要があります。
Java 7をまだ使用していない場合は、try-finally
ブロックを使用します。このブロックでは、閉じたリソースを取得したときと逆の順序で手動で閉じます。例: JDBCでConnection、Statement、ResultSetを閉じる頻度はどれくらいですか?
接続のパフォーマンスが心配な場合は、代わりに接続プーリングを使用する必要があります。これは、多くのJava EEアプリケーションサーバーに組み込まれています。Tomcatのようなベアボーンサーブレットコンテナーでさえもサポートします。サーバー自体にJNDIデータソースを作成し、WebアプリケーションにDataSource
。既に透過的に接続プールになっています。以下のリストの最初のリンクで例を見つけることができます。
Select
クエリのみを実行している場合(searchUser
はデータ選択のみのように聞こえます)、スレッドの競合を除き、問題はありません。
私の知る限り、Connection
は一度に1つのクエリしか処理できないため、単一のインスタンスを使用することで、データベースアクセスを本質的にシリアル化できます。しかし、これは必ずしも意味するものではなく、マルチスレッド環境でこのようなデータベースにアクセスすることは常にsafeです。同時アクセスがインターリーブされている場合、依然として問題がある可能性があります。