12

JDBCを使用してPostgresデータベースと通信しています。アプリ全体が単一の接続で実行されている場合、つまり、への呼び出しは1回だけです。

DriverManager.getConnection("jdbc:postgresql://host:5432/database", user, pass);

しかし、このConnectionオブジェクトはJavaの複数のスレッド間で共有されます。Javaスレッドがインターリーブする可能性があることを考えると、SQLトランザクション(BEGINおよびCOMMITスタイル)を使用しようとすると、非常に混乱して壊れてしまうと思いますか?オブジェクトは、ConnectionどのJavaスレッドがクエリを実行するためにそれを使用しているかを「知っています」か?

ConnectionJavaスレッドごとに1つのオブジェクトがあり、SQLトランザクションをそのように使用する必要がありますか?または、Javaですべてのトランザクション分離を使用して実行する必要がありますsynchronizedか?

4

3 に答える 3

14

既存の回答について詳しく説明します。

PgJDBCのConnectionオブジェクトはスレッドセーフですが、ステートメントレベルでのみ使用できます。自動コミットモードで複数のスレッドによって使用された場合、クラッシュしたり間違った結果を生成したりすることはありませんが、異なるスレッドのトランザクションを分離することはありません。ドキュメントによると、そのために接続プールを使用する必要があります。

実際には、複数のスレッド間の接続を使用する方法はたくさんあります。

  • 接続をフェッチし、それらを使用して作業を実行し、それらをプールに戻す内部接続プールを使用します。これは、ほとんどのアプリケーションにとって非常に望ましいオプションです。Java用のJDBC接続プールの実装は多数存在するため、独自に実装しないでください。dbcpc3p0は2つの一般的な実装ですが、サーブレット環境またはアプリサーバーを使用している場合は、通常、独自の接続プールを使用するのではなく、サーバーの接続プールを使用する必要があります。

  • pgbouncerやpgpool-IIなどの外部接続プールを使用して、接続を自由に開閉します。これは少し遅く、ほとんどの場合、アプリケーションが接続を内部でプールできない、またはさまざまな理由で接続をプールすべきでない場合に使用されるオプションです。DBへの合計接続数を制限し、それらを複数のアプリケーションまたはアプリインスタンス間で共有する必要がない限り、おそらくこれを行う必要はありません。

  • プールを使用せず、接続を自由に開閉します。これはひどく非効率的です。しないでください。

  • スレッドローカルストレージを使用して、スレッドごとに接続を維持します。これは機能しますが、開いている各接続がアイドル状態のときにデータベースサーバーのリソースを拘束するため、非常に非効率的です。トランザクションプーリングモードでPgBouncerなどの外部接続プールを使用しない限り、これを行わないでください。使用する場合は問題ありません。

  • 単一の接続のみを使用し、トランザクションをsynchronizedブロックにラップして、インスタンスで同期しConnectionます。これは機能し、データベース接続を効率的に使用しますが、スレッドのパフォーマンスを制限します。一般的に、おもちゃや便利なアプリ以外には適したデザインではありません。

  • 専用スレッドとの接続は1つだけ使用してください。他の接続に、FIFOキュー、プロデューサー/コンシューマースタイルを介してそのスレッドに実行される作業を説明するデータ構造を渡させます。これは、スレッドがほとんどの時間をCPUを多用する作業やその他のデータベース以外の作業に費やし、限られたデータベースアクセスのみを必要とする場合に機能します。接続プールを使用する代わりにそれを使用するほとんどの唯一の理由は、何らかの外部的な理由で単一の接続を使用するように制約されている場合ですが、そうであれば、それはまともなオプションになる可能性があります。

ただし、一般的には、接続プールを使用してそれで済ます必要があります。

于 2013-03-26T23:58:23.333 に答える
5

Javaスレッドがインターリーブする可能性があることを考えると、 SQLトランザクション(BEGINおよびCOMMITスタイル)を使用しようとすると、非常に混乱して壊れてしまうだけだと思いますか?

これは絶対に正しいです。

Connectionオブジェクトは、どのJavaスレッドがクエリを実行するためにそれを使用しているかを「認識」していますか?

いいえ、違います。

Javaスレッドごとに1つのConnectionオブジェクトがあり、SQLトランザクションをそのように使用する必要がありますか?

はい、これはそれを行う1つの方法です。「スレッドごとの接続」割り当ての欠点は、必要以上の接続を開く可能性があり、リソースの使用が最適化されない可能性があります。また、スレッドが必要とする場合にのみ接続を開き、RDBMSアクセスでスレッドが完了したら接続を閉じることもできます。このルートを使用する場合は、接続プールを使用して、接続を複数回再開するオーバーヘッドを減らすようにしてください。

于 2013-03-26T16:25:14.640 に答える
2
Does the Connection object 'know' which Java thread is using it to make queries?

いいえ、接続オブジェクトはどのJavaスレッドがそれを使用しているかを知りません。

Javaスレッドごとに1つのConnectionオブジェクトがあり、SQLトランザクションをそのように使用する必要がありますか?または、同期を使用してJavaですべてのトランザクション分離を実行する必要がありますか?

データベース固有のjdbc接続プールデータソースを使用してトランザクションを実行する必要があります。これにより、接続オブジェクトが使用されなくなったときに、接続がガベージコレクションされずにプールに戻ります。このようにして、アプリケーションサーバーは接続の初期化パフォーマンスを最適化できます。

また、更新操作中に同期メソッド呼び出しを使用する必要があります。これにより、本番環境での操作がはるかに安全になります。

于 2013-03-26T16:35:19.870 に答える