15

データベース接続が IDisposable を実装する理由を誰かに説明しようとしていたとき、「接続を開く」が実際に何を意味するのかよくわからないことに気付きました。
だから私の質問は - 接続を開くときにc#は実際に何をしますか?

ありがとうございました。

4

3 に答える 3

26

接続の実装には、実際には2つのクラスが関係しています(実際にはそれ以上ですが、単純化しています)。

これらの1つは、コードで使用する実装IDbConnection(、、、SQLConnectionなど)です。もう1つは、アセンブリの内部にあり、コードからは見えない「実際の」接続オブジェクトです。今のところ、これを「」と呼びますが、実際の名前は実装によって異なります(たとえば、Npgsqlでは、実装に最も精通している場合、クラスはと呼ばれます)。NpgsqlConnectionOracleConnectionRealConnectionNpgsqlConnector

を作成するときIDbConnection、にはありませんRealConnection。データベースで何かをしようとすると失敗します。あなたがOpen()それをすると、次のことが起こります:

  1. プーリングが有効になっていRealConnectionて、プールにが存在する場合は、それを両端キューにして、のRealConnection用にしIDbConnectionます。
  2. プーリングが有効になっていて、存在するオブジェクトの総数RealConnectionが最大サイズよりも多い場合は、例外をスローします。
  3. それ以外の場合は、新しいを作成しますRealConnection。それを初期化します。これには、ある種のネットワーク接続(TCP / IPなど)またはファイルハンドル(Accessなど)を開き、データベースのプロトコルを使用してハンドシェイク(データベースの種類によって異なります)を実行し、接続を承認します。これは、のRealConnectionになりIDbConnectionます。

で実行さIDbConnectionれる操作はRealConnection、ネットワーク接続(またはその他)で実行される操作に変換されます。IDataReader結果は、プログラミングに一貫したインターフェイスを提供するために、実装などのオブジェクトに変換されます。

IDataReaderで作成された場合、CommandBehavior.CloseConnectionそのデータリーダーはの「所有権」を取得しRealConnectionます。

電話をかけるClose()と、次のいずれかが発生します。

  1. プールしている場合、およびプールがいっぱいでない場合、オブジェクトは後の操作で使用するためにキューに入れられます。
  2. それ以外の場合はRealConnection、接続を終了するためのプロトコル定義の手順(接続がシャットダウンされることをデータベースに通知する)を実行し、ネットワーク接続などを閉じます。オブジェクトはスコープから外れ、ガベージコレクションに使用できるようになります。

例外は、CommandBehavior.CloseConnectionケースが発生した場合です。この場合、これをトリガーするのは、Close()またはDispose()で呼び出されます。IDataReader

電話をかけるとDispose()、と同じことが起こりClose()ます。違いは、Dispose()「クリーンアップ」と見なされ、で動作する可能性があるusing一方Close()で、ライフタイムの途中で使用され、その後に使用される可能性があることOpen()です。

オブジェクトの使用RealConnectionとそれらがプールされているという事実のために、接続の開閉は、比較的重いものから比較的軽いものに変わります。したがって、接続を開くオーバーヘッドを回避するために接続を長時間開いたままにしておくことが重要ではなく、オーバーヘッドを処理するため、できるだけ短時間、接続を開いたままにしておくことが重要になりRealConnectionます。それらを使用すると、プールされた接続が使用間でより効率的に共有されます。

また、すでに呼び出していることは問題ありません(状態に関係なく、実際にすでに呼び出されDispose()ている場合でも、常に安全に呼び出すことができるという規則があります)。したがって、手動で呼び出している場合でも、への呼び出しの前に例外が発生する場合をキャッチするために、接続をブロックに含めることをお勧めします。唯一の例外は、実際に接続を開いたままにしておきたい場合です。で作成されたものを返したとしましょう。この場合、は破棄しません、リーダーは破棄します。IDbConnectionClose()Dispose()Close()usingClose()IDataReaderCommandBehavior.CloseConnectionIDbConnection

接続の破棄に失敗した場合、RealConnectionは再利用のためにプールに戻されないか、シャットダウン手順が実行されます。プールが制限に達するか、基盤となる接続の数が増えてパフォーマンスが低下し、それ以上の作成がブロックされます。最終的にはファイナライザーRealConnectionが呼び出され、これが修正される可能性がありますが、ファイナライズはダメージを軽減するだけであり、信頼することはできません。(ファイナライザーは、管理されていないリソースを保持している、および/またはシャットダウンを実行する必要がIDbConnectionあるため、ファイナライザーは必要ありません)。RealConnection

また、これを超えた実施に特有の処分要件があると考えるのも合理的でありIDbConnection、上記を分析した結果、必要ないと思われる場合でも処分する必要があります(例外は、CommandBehavior.CloseConnectionすべての処分負担を通過する場合です)。にIDataReader、しかしそれからその読者を処分することは同じように重要です)。

于 2010-10-02T13:29:28.027 に答える
4

良い質問。

SQL 接続の「内部」作業に関する私の (やや限られた知識) から、次のような多くの手順が含まれます。

フードの下のステップ

  1. 物理的なソケット/パイプが開かれている (ODBC などの特定のドライバーを使用)
  2. SQL Server とのハンドシェイク
  3. ネゴシエートされた接続文字列/資格情報
  4. トランザクションのスコープ

接続プーリングは言うまでもなく、何らかのアルゴリズムが関係していると思います(接続文字列が既存のプールの接続文字列と一致する場合、接続はプールに追加され、そうでない場合は新しいものが作成されます)

IDiposable

SQL 接続に関しては、IDisposable を実装して、(using ディレクティブまたは明示的に) dispose を呼び出すと、接続が接続プールに戻されるようにします。これは、単純な古い sqlConnection.Close() とはまったく対照的です。これは一時的に閉じるだけですが、後で使用するためにその接続を予約します。

私の理解では、.Close() はデータベースへの接続を閉じますが、.Dispose() は .Close() を呼び出してから、管理されていないリソースを解放します。

これらの点を念頭に置いて、少なくとも IDisposable を実装することをお勧めします。

于 2010-10-02T12:54:30.280 に答える
0

上記の回答に追加する...重要なのは、「接続を開く」ときに、標準のガベージコレクションよりも回復に時間がかかるリソース、つまり何らかのオープンソケット/パイプ/IPCが割り当てられる可能性があることです。Dispose() メソッドはこれらをクリーンアップします。

于 2010-10-02T13:04:24.563 に答える