データベース接続が IDisposable を実装する理由を誰かに説明しようとしていたとき、「接続を開く」が実際に何を意味するのかよくわからないことに気付きました。
だから私の質問は - 接続を開くときにc#は実際に何をしますか?
ありがとうございました。
データベース接続が IDisposable を実装する理由を誰かに説明しようとしていたとき、「接続を開く」が実際に何を意味するのかよくわからないことに気付きました。
だから私の質問は - 接続を開くときにc#は実際に何をしますか?
ありがとうございました。
接続の実装には、実際には2つのクラスが関係しています(実際にはそれ以上ですが、単純化しています)。
これらの1つは、コードで使用する実装IDbConnection
(、、、SQLConnection
など)です。もう1つは、アセンブリの内部にあり、コードからは見えない「実際の」接続オブジェクトです。今のところ、これを「」と呼びますが、実際の名前は実装によって異なります(たとえば、Npgsqlでは、実装に最も精通している場合、クラスはと呼ばれます)。NpgsqlConnection
OracleConnection
RealConnection
NpgsqlConnector
を作成するときIDbConnection
、にはありませんRealConnection
。データベースで何かをしようとすると失敗します。あなたがOpen()
それをすると、次のことが起こります:
RealConnection
て、プールにが存在する場合は、それを両端キューにして、のRealConnection
用にしIDbConnection
ます。RealConnection
が最大サイズよりも多い場合は、例外をスローします。RealConnection
。それを初期化します。これには、ある種のネットワーク接続(TCP / IPなど)またはファイルハンドル(Accessなど)を開き、データベースのプロトコルを使用してハンドシェイク(データベースの種類によって異なります)を実行し、接続を承認します。これは、のRealConnection
になりIDbConnection
ます。で実行さIDbConnection
れる操作はRealConnection
、ネットワーク接続(またはその他)で実行される操作に変換されます。IDataReader
結果は、プログラミングに一貫したインターフェイスを提供するために、実装などのオブジェクトに変換されます。
IDataReader
で作成された場合、CommandBehavior.CloseConnection
そのデータリーダーはの「所有権」を取得しRealConnection
ます。
電話をかけるClose()
と、次のいずれかが発生します。
RealConnection
、接続を終了するためのプロトコル定義の手順(接続がシャットダウンされることをデータベースに通知する)を実行し、ネットワーク接続などを閉じます。オブジェクトはスコープから外れ、ガベージコレクションに使用できるようになります。例外は、CommandBehavior.CloseConnection
ケースが発生した場合です。この場合、これをトリガーするのは、Close()
またはDispose()
で呼び出されます。IDataReader
電話をかけるとDispose()
、と同じことが起こりClose()
ます。違いは、Dispose()
「クリーンアップ」と見なされ、で動作する可能性があるusing
一方Close()
で、ライフタイムの途中で使用され、その後に使用される可能性があることOpen()
です。
オブジェクトの使用RealConnection
とそれらがプールされているという事実のために、接続の開閉は、比較的重いものから比較的軽いものに変わります。したがって、接続を開くオーバーヘッドを回避するために接続を長時間開いたままにしておくことが重要ではなく、オーバーヘッドを処理するため、できるだけ短時間、接続を開いたままにしておくことが重要になりRealConnection
ます。それらを使用すると、プールされた接続が使用間でより効率的に共有されます。
また、すでに呼び出していることは問題ありません(状態に関係なく、実際にすでに呼び出されDispose()
ている場合でも、常に安全に呼び出すことができるという規則があります)。したがって、手動で呼び出している場合でも、への呼び出しの前に例外が発生する場合をキャッチするために、接続をブロックに含めることをお勧めします。唯一の例外は、実際に接続を開いたままにしておきたい場合です。で作成されたものを返したとしましょう。この場合、は破棄しませんが、リーダーは破棄します。IDbConnection
Close()
Dispose()
Close()
using
Close()
IDataReader
CommandBehavior.CloseConnection
IDbConnection
接続の破棄に失敗した場合、RealConnection
は再利用のためにプールに戻されないか、シャットダウン手順が実行されます。プールが制限に達するか、基盤となる接続の数が増えてパフォーマンスが低下し、それ以上の作成がブロックされます。最終的にはファイナライザーRealConnection
が呼び出され、これが修正される可能性がありますが、ファイナライズはダメージを軽減するだけであり、信頼することはできません。(ファイナライザーは、管理されていないリソースを保持している、および/またはシャットダウンを実行する必要がIDbConnection
あるため、ファイナライザーは必要ありません)。RealConnection
また、これを超えた実施に特有の処分要件があると考えるのも合理的でありIDbConnection
、上記を分析した結果、必要ないと思われる場合でも処分する必要があります(例外は、CommandBehavior.CloseConnection
すべての処分負担を通過する場合です)。にIDataReader
、しかしそれからその読者を処分することは同じように重要です)。
良い質問。
SQL 接続の「内部」作業に関する私の (やや限られた知識) から、次のような多くの手順が含まれます。
フードの下のステップ
接続プーリングは言うまでもなく、何らかのアルゴリズムが関係していると思います(接続文字列が既存のプールの接続文字列と一致する場合、接続はプールに追加され、そうでない場合は新しいものが作成されます)
IDiposable
SQL 接続に関しては、IDisposable を実装して、(using ディレクティブまたは明示的に) dispose を呼び出すと、接続が接続プールに戻されるようにします。これは、単純な古い sqlConnection.Close() とはまったく対照的です。これは一時的に閉じるだけですが、後で使用するためにその接続を予約します。
私の理解では、.Close() はデータベースへの接続を閉じますが、.Dispose() は .Close() を呼び出してから、管理されていないリソースを解放します。
これらの点を念頭に置いて、少なくとも IDisposable を実装することをお勧めします。
上記の回答に追加する...重要なのは、「接続を開く」ときに、標準のガベージコレクションよりも回復に時間がかかるリソース、つまり何らかのオープンソケット/パイプ/IPCが割り当てられる可能性があることです。Dispose() メソッドはこれらをクリーンアップします。