Delphi で COM+ ステータス情報を維持する方法
劉暁明(サイファーリウ)
問題は次のように始まります。異なるデータベースに接続するために COM+ を作成する必要があります。データベースごとに COM+ を確立する必要があると言う友人もいるかもしれませんが、これは私のシステムでは実行できません。私たちが作っているのは教育支援システムで、利用者は学校(もちろん学校の先生、生徒、保護者も含みます)です。このデータベースの構造は同じです。もちろん、データベース間の関係を調整するための管理データベースもあります。学校のユーザーが追加されるたびに、顧客が使用できる新しいデータベースがアクティブになります。つまり、データベースの数は常に増加しており、学校ごとに異なるデータベースを開発することはありません。クライアント側では、データベースごとに 1 つのセットを開発するのではなく、1 つの COM+ セットのみを使用します。したがって、COM+ のユーザーの ID に基づいて異なるデータベースに接続できるようにする必要があります。
明らかに、この COM+ は、呼び出し元 (クライアント アプリケーションまたは他のミドルウェア) が接続先のデータベースを選択できるようにするメソッドを提供する必要があります。実際には、ユーザーの ID に基づいて管理ライブラリ内のデータベースにクエリを実行します。ここでは、問題を単純化するために、呼び出し元がデータベースの名前をすでに知っており、このデータベースの呼び出しを直接要求すると考えます。
プライベート メンバー DBName:string を COM+ クラスに追加して、接続するデータベースの名前を保存します。値を設定するためのメソッドも提供する必要があります。最初はこのように書きました。
手順 TmtsDBConn.ConnectTo(sDBName:string);
始める
試す
DB名:=sDB名;
SetComplete;
を除外する
SetAbort;
終わり;
終わり;
次に、ADOConnection、ADODataSet、DataSetProvider コントロールをそれぞれ adoc、adods、dsp という名前で配置します。それらの間の接続関係を設定し、adoc の接続文字列を接続データベース "DB1" (デフォルト値) に設定し、次に adoc の BeforeConnect イベントで次のように設定します。
adoc.ConnectionString:=ConnectStringA+'初期カタログ='+DBName+';'+ConnectStringC;
ここでの ConnectStringA と ConnectStringC は、次のように接続文字列を動的に構築するために事前に設定された文字列定数です。
定数
ConnectStringA='Provider=SQLOLEDB.1;PassWord=2003;Persist Security Info=True;User ID=sa;';
ConnectStringB='初期カタログ=DB1;';
ConnectStringC='データ ソース=server3;準備のプロシージャを使用=1;自動翻訳=True;パケット サイズ=4096;ワークステーション ID=LXM;データの暗号化を使用=False;可能な場合は列照合によるタグ付け=False';
この COM+ をコンパイルしてインストールします。次に、それを呼び出すクライアント プログラムを作成します。
クライアント プログラムに DCOMConnection を配置し、それに接続して COM+ サーバーを記述し、ClientDataSet を配置して、その RemoteServer プロパティと Provider プロパティを設定して、その CommandText に SQL ステートメントを記述します。次に、DataSource コントロールと DBGrid コントロールを挿入して、それらの間の接続を確立します。最後にボタンを配置し、その Click イベントに次のようにします。
Dcomconnection1.Connected:=true;
Dcomconnection1.AppServer.connect('DB2');
ClientDataset1.Active:=true;
Dcomconnection1.Connected:=false;
このコードは、DB2 データベース内のデータにアクセスできるかどうかをテストします。しかし、その結果、ボタンをクリックすると常にエラーが報告されます。その理由は何でしょうか。
COM+ プロジェクトに戻ってデバッグし、ConnectTo および adocBeforeConnect にブレークポイントを設定すると、プログラムが実行されていることを確認します。
DB名:=sDB名;
実行すると確かにDBNameの値は「DB2」に設定されていますが、実行すると
adoc.ConnectionString:=ConnectStringA+'初期カタログ='+DBName+';'+ConnectStringC;
, DBNameがまた空文字になってしまったのでエラーが発生しました。
DBName の値が失われるのはなぜですか? SetComplete メソッドが ConnectTo で呼び出されていることがわかります。SetComplete メソッドは、COM+ がタスクを完了したとみなして COM+ オブジェクトを解放します。そのため、データベースに接続すると、新しい COM+ が作成され、その DBName は当然のことです。ヌル。
理由を見つけて、SetComplete を EnableCommit に変更し、クライアントを実行しました。最終的に、クライアントは正常に実行され、DB2 データベース内のデータを取得しました。
ただし、クライアント プログラムで、ClientDataSet1 を開いた後、ClientDataSet2 を開いて、DB2 内のデータへのアクセスを続行しようとしましたが、別のエラーが報告されました。プログラムを次のように変更します
Dcomconnection1.AppServer.connect('DB2');
ClientDataset1.Active:=true;
ClientDataset1.Active:=false;
ClientDataset1.Active:=true;
ClientDataSet が 1 つだけの場合でも、ClientDataSet を閉じた後に再度開くとエラーが発生します。
しかし、クライアントが書いた場合、
Dcomconnection1.AppServer.connect('DB2');
ClientDataset1.Active:=true;
Dcomconnection1.AppServer.connect('DB2');
ClientDataset2.Active:=true;
正常に実行できます。しかし、これは非常に見苦しいように思えます。データベースに接続した後に COM+ が自動的に解放されるのはなぜでしょうか。
TmtsDataModule には AutoComplete 属性があり、デフォルト値は true であるため、データベースに接続した後も自身を解放します。
AutoComplete を false に設定した後も、COM+ の OnActivate イベントでエラーが発生しました。アクティブ化されたときに AutoComplete 属性が自動的に true に設定されていたため、初めてデータベースに接続した後も解放されてしまうことがわかりました。自体。
COM+ の OnOnActivate イベントに次のように記述します。
オートコンプリート:=false;
クライアントが 1 回接続し、データベースに複数回アクセスする場合は問題ありません。
ただし、この場合、COM+ は自動的に解放されません。COM+ にメソッドを追加し、このメソッドで SetComplete を実行し、クライアントが COM+ を終了した後にこのメソッドを呼び出して COM+ を解放する必要があります。
上記の検討の結果、次の結論に達しました。COM+ では、デフォルトでステートレスであるため、状態情報を維持したい場合は、クライアントによって呼び出されるたびに、ステートレスであるかどうかが判断されます。自動的に解放されるはずですが、解放されたくない場合は手動で介入する必要があり、最後に手動で解放する必要があります。