2

私はこれらのコードを持つサーバーを持っています:

procedure TFrmMain.TCPServerExecute(AContext: TIdContext);
begin
      Res := DoRegister(Name,Family,Username,Password);
end;

function TFrmMain.DoRegister(Name,Family,Username,Password:string): bool;
var
  Qry: TSQLQuery;
begin
  Qry := TSQLQuery.Create(nil);
  try
    Qry.SQLConnection := FrmConnect.SQLConnection;
    Qry.SQL.Text :='INSERT INTO `table` ...';
    Qry.ExecSQL();
  finally
    Qry.Free;
  end;
  Result := True;
end;

さまざまなスレッドの1つのテーブルへのアクセスに問題はありますか?そして、Onexecuteイベントで使用するのは完全に危険ですか?

返信ありがとうございます。

だから、それは異なるスレッドに対して異なる接続を行うための本当の方法ですか?

var
  Qry: TSQLQuery;
  SqlCon: TSQLConnection;
Begin
  SqlCon := TSQLConnection.Create(nil);
  Qry := TSQLQuery.Create(nil);
  try
    SqlCon := FrmConnect.SQLConnection;
    Qry.SQLConnection := SqlCon;
  finally
    SqlCon.Free;
    Qry.Free;
  end;
end;
4

4 に答える 4

2

データベース接続には接続プールを使用します。次に、すべてのスレッドは、必要な場合にのみプールからの接続を要求し(現在、プールに空き接続がない場合はブロックされる可能性があります)、それを使用して最終的にプールに返します。プールには、並行スレッドよりも必要な接続が少なく、必要なときに接続がすでに存在するという利点があります。

于 2010-08-21T14:40:01.167 に答える
2

はいといいえ。異なるスレッドから単一のテーブルにアクセスできますが、安全にアクセスするには、スレッドごとにTSQLConnectionインスタンスが必要です。

アップデート

スレッドごとに異なる接続をインスタンス化することは問題ありません。これは、ほとんどのWebページでも常に行われていることです(asp、php、または...を使用したサーバー側スクリプトはステートレス実行を意味するため、接続は通常、次の要求まで存続せず、再確立する必要があります)。

オーバーヘッドが心配な場合は、vcldeveloperが提案するような単一の接続の使用を検討できます。他のスレッドによって変更されたその「接続スレッド」によって使用される変数とメンバーフィールド(たとえば、実行されるSQLを受け取るフィールドメンバー)が、何らかの同期メカニズムによって保護されていることを確認する必要があります。 。

mjustinによって提案されたのと同じことが接続プールにも当てはまりますが、その場合、接続プールは同期メカニズムによって保護される必要があります。

于 2010-08-21T11:18:44.190 に答える
2

DBにアクセスする各スレッドには独自の接続が必要です。複数のスレッド間でDB接続を共有することはできません。OnExecuteイベントは、要求元のクライアントに対応するスレッドのコンテキストで呼び出されるため、呼び出されるたびにワーカースレッド内で実行され、そのようなスレッドには独自のDB接続が必要です。

ワーカースレッドごとに新しい接続を確立したくない場合。1つのオプションは、単一のスレッドをDB接続専用にし、すべてのDB操作をそのスレッドに委任することです。たとえば、他のスレッドはINSERT SQLステートメントをそのDBスレッドのキューに送信し、そのDBスレッドはそれらを1つ実行します-単一のDB接続を使用して1つずつ。もちろん、このアプローチを採用した場合、すべてのDB負荷は単一のスレッドにかかり、非常に多くのDB操作がある場合、そのDBスレッド自体がパフォーマンスのボトルネックになる可能性があります。さらに、このアプローチを採用すると、各スレッドがDBスレッドにDBクエリの実行を要求するたびに同期手法を使用することを除いて、クエリの実行は非同期になります。

また、DBアクセスコンポーネントがADOの場合は、CoInitializeとCoUninitializeを呼び出す必要があることに注意してください。これは、Delphiランタイムがメインスレッドに対してのみ実行し、自分で作成した他のスレッドに対しては実行しないためです。

于 2010-08-21T13:00:54.767 に答える
2

2番目のコードフラグメントが正しくありません。接続文字列をコピーする必要があるときに、グローバル接続で新しい接続を上書きしています。また、そのグローバルを解放しているため、アプリケーションの残りの部分で問題が発生する可能性があります。TSQLConnectionクラスの詳細に応じて、次のようになります。

SqlCon := TSQLConnection.Create(nil); // create
Qry := TSQLQuery.Create(nil);
try
  //SqlCon := FrmConnect.SQLConnection; // overwrite!!!
  SqlCon.ConnectionString :=  FrmConnect.SQLConnection.ConnectionString;
  SqlCon.Active := true;
  Qry.SQLConnection := SqlCon;
  ...

データベース接続プールが必要な場合、接続は通常スレッド固有であるため、非常に注意が必要です。スレッドごとに1つ必要であり、スレッド間でそれらを渡すことはできません。したがって、それをサポートするために多くのコードを書くことになります。

現在、OmniThreadLibraryを使用しており、新しいデータベース接続を返すファクトリメソッドがあります。これにより、タスクをフィードするスレッドプールが得られるため、特定のタスクは実行時に既存のスレッドにバインドされますが、スレッドの寿命はかなり長くなります。これを取得するために作成する必要のあるコードは非常に小さいです(私はADOを使用しています)。

type
    // a factory to generate new instances of our thread-specific data
    IThreadPoolData = interface
        ['{14917B01-6613-4737-B87E-0046789D4284}']
        function GetConnection: TADOConnection;
        function GetStoredProc: TADOStoredProc;
    end;

    TThreadPoolData = class(TInterfacedObject, IThreadPoolData)
    strict private
        FADOConnection: TADOConnection;
        FStoredProc: TADOStoredProc; // lazy creation!
    public
        constructor Create(aConnectionString: string); overload;
        destructor Destroy; override;
        function GetConnection: TADOConnection;
        function GetStoredProc: TADOStoredProc;
    end;

// create the connection here so thread creation is slow but using it 
// is (relatively) fast

constructor TThreadPoolData.Create(aConnectionString: string);
begin
    FADOConnection := TADOConnection.Create(nil);
    FADOConnection.LoginPrompt := false;
    FADOConnection.ConnectionString := aConnectionString;
    FADOConnection.ConnectOptions := coAsyncConnect;
    FADOConnection.Connected := true;
end;

destructor TThreadPoolData.Destroy;
begin
    FADOConnection.Connected := false;
    if assigned(FStoredProc) then
        FreeAndNil(FStoredProc);
    FreeAndNil(FADOConnection);
end;

独自のスレッドまたは接続プールを作成する場合は、同様のことを行う必要があります。

于 2010-08-23T01:19:08.587 に答える