2013-04-27 13 views
5

データベースからデータをフェッチする必要があるたびに呼び出すことができるクエリコードがあり、スレッド化する必要があります。私はこのコードを再利用できるように、スレッド内でこれを実装する方法は不明ですが、基本的には、このコードをスレッド内に配置します。スレッド内で単純なデータベースクエリを作成する方法を知っていますが、再利用できるものが必要です。誰かが私にこれについての例を見つけることができる場所に私を指摘することができますか、または例を提供するのに十分親切ですか?スレッド型Delphi ADOクエリ

は、ここに私のサンプルデータベースのクエリです:

function TDBConnection.SQLOpen(const SQLStr: String): TDataSet; 
var 
    i: Integer 
begin 
    try 
    Result := TADOQuery.Create(DBConnect.FDatabaseConection); 
    TADOQuery(Result).Connection:=DBConnect.FDatabaseConnection; 
    TADOQuery(Result).CommandTimeOut:=30; 
    TADOQuery(Result).SQL.Text := SQLStr; 
    TADOQuery(Result).Open; 
    except 

    end; 
end; 

そして、これは私が上記の関数を呼んでいるかのサンプルです:再利用のために

function TDBConnection.GetUserInfo: Boolean; 
var 
    sqlStr: String; 
    Database: TDataset; 
begin 
    sqlStr:= 'SELECT FIELD1, FIELD2, FIELD3 FROM TABLE1'; 
    try 
    Dataset := SQLOpen(sqlStr); 
    if not Dataset.IsEmpty then 
    begin 
     //pass result to StringGrid 
    end; 
    finally 
    FreeAndNil(SQLParams); 
    FreeAndNil(Dataset); 
    end; 
end; 
+0

なぜあなたはスレッドにしたいですか?クエリが実行されている間に他の処理を実行したい場合は、非同期クエリ(別のスレッドでクエリを実行する)を使用できます。 – Rob

+0

こんにちは、ロブ、提案のおかげで。しかし、私は、非同期クエリを使用すると、多くのユーザーがハンドルやメモリーリークに問題があると読んだことがあります。 –

+0

私はそれを見たことがありません。私は非同期ADOクエリを常に実行している一週間に数週間実行する自律型(Delphi)ソフトウェアを持っています。私は実行時に100000000の非同期クエリを定期的に実行する他のC++コードをいくつか持っています。 – Rob

答えて

4

がparameterinformationsを持つ配列を使用します。
すべてのスレッドは、独自のConnectionで独自のAdodatasetを作成します。
レコードセットは、スレッド終了後に表示および編集するために使用できます。
実際のアプリケーションでスレッドインスタンスを処理するには、追加する必要があります。

unit ThreadedAdoDataset; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, StdCtrls, DB, ADODB, Grids, DBGrids; 

type 

    TFieldInfoRecord = Record // as far as sometimes parametertypes can not be detected by 
    DataType: TFieldType; // Ado on his own, provide all needed informations 
    Name: String; 
    Size: Integer; 
    Value: Variant; 
    End; 

    TFieldInfoArray = Array of TFieldInfoRecord; 

    TDBThread = Class(TThread) 
    Constructor Create(Const ConnectionString, SQL: String; 
     FDArray: TFieldInfoArray); 
    private 
    FConnectionString, FSQL: String; 
    FFDArray: TFieldInfoArray; 
    FRecordSet: _RecordSet; 
    Protected 
    Procedure Execute; override; 
    public 
    Property RecordSet: _RecordSet read FRecordSet; 
    End; 

    TForm7 = class(TForm) 
    ADOConnection1: TADOConnection; 
    Button1: TButton; 
    ADODataSet1: TADODataSet; 
    DataSource1: TDataSource; 
    DBGrid1: TDBGrid; 
    procedure FormCreate(Sender: TObject); 
    procedure Button1Click(Sender: TObject); 
    private 
    procedure ThreadTerminate(Sender: TObject); 
    { Private-Deklarationen } 
    public 
    { Public-Deklarationen } 
    end; 

var 
    Form7: TForm7; 

implementation 

uses ActiveX; 
{$R *.dfm} 

procedure TForm7.Button1Click(Sender: TObject); 
var 
    FDArray: TFieldInfoArray; 
    I: Integer; 
begin 
    // prepare parameterinformations 
    SetLength(FDArray, 1); 
    FDArray[0].Name := 'cn'; 
    FDArray[0].DataType := ftString; 
    FDArray[0].Size := 20; 
    FDArray[0].Value := '%ue%'; 

    for I := 0 to 10 do // testrun with 11 threads 

    With TDBThread.Create(ADOConnection1.ConnectionString, 
     'select * from Composition where Componame like :cn', FDArray) do 
    begin 
     FreeOnTerminate := true; 
     // assign the wished procedure to ba called on terminate 
     OnTerminate := ThreadTerminate; 
    end; 

end; 

procedure TForm7.ThreadTerminate(Sender: TObject); 
begin 
    // example of assigning the recordset of the thread for displaying and editing 
    // NOTE for editing the connection of ADODataSet1 has to be fitting to the threadcall 
    ADODataSet1.RecordSet := TDBThread(Sender).RecordSet; 
end; 

procedure TForm7.FormCreate(Sender: TObject); 
begin 
    ReportMemoryLeaksOnShutDown := true; 
end; 


{ TDBThread } 

constructor TDBThread.Create(const ConnectionString, SQL: String; 
    FDArray: TFieldInfoArray); 
var 
    I: Integer; 
begin 
    inherited Create(false); 
    FConnectionString := ConnectionString; 
    FSQL := SQL; 
    SetLength(FFDArray, Length(FDArray)); 
    for I := 0 to High(FDArray) do 
    begin 
    FFDArray[I].DataType := FDArray[I].DataType; 
    FFDArray[I].Size := FDArray[I].Size; 
    FFDArray[I].Name := FDArray[I].Name; 
    FFDArray[I].Value := FDArray[I].Value; 
    end; 
end; 

procedure TDBThread.Execute; 
var 
    I: Integer; 
begin 
    inherited; 
    CoInitialize(nil); 
    try 
    With TADODataSet.Create(nil) do 
     try 
     CommandTimeOut := 600; 
     ConnectionString := FConnectionString; 
     // use own connection for the dataset 
     // will requite a conncetionsstring including all 
     // information for loggon 
     Commandtext := FSQL; 
     Parameters.ParseSQL(FSQL, true); // extract parameters 
     for I := Low(FFDArray) to High(FFDArray) do // set parametervalues 
     begin 
      Parameters.ParamByName(FFDArray[I].Name).DataType := FFDArray[I] 
      .DataType; 
      Parameters.ParamByName(FFDArray[I].Name).Size := FFDArray[I].Size; 
      Parameters.ParamByName(FFDArray[I].Name).Value := FFDArray[I].Value; 
     end; 
     Open; 
     FRecordSet := RecordSet; // keep recordset 
     finally 
     Free; 
     end; 
    finally 
    CoUnInitialize; 
    end; 
end; 

end. 
+0

@ kobikありがとう、一種の過度に.. – bummi

+0

@bummi、このコードサンプルのおかげで、私は私のプロジェクトでこれを試してみましょう。 –

関連する問題