2013-04-27 65 views
5

我有一個查詢代碼,我可以調用每次我需要從數據庫中獲取數據,我希望它是線程。不知道如何在一個線程中實現這個,所以我可以重用這段代碼,基本上,我希望這個代碼在一個線程中。我知道如何在線程內部創建一個簡單的數據庫查詢,但想要可重用的東西。任何人都可以指出我在哪裏可以找到這方面的例子,或者足夠提供一個例子嗎?螺紋德爾福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; 

這是我如何調用上述功能的示例:使用帶parameterinformations數組

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 2013-04-27 11:41:12

+0

嗨羅布,感謝您的建議。但是我讀過一些地方,很多用戶在使用異步查詢時遇到了句柄和內存泄漏問題。 – 2013-04-28 01:00:30

+0

我還沒有看到。我有自主的(Delphi)軟件,每次運行數週,不斷進行異步ADO查詢。我有一些其他的C++代碼,可以在運行時定期處理100000000個異步查詢。 – Rob 2013-04-28 11:05:48

回答

4

可重用性。
每個線程創建一個擁有自己的連接的自己的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 2013-04-28 10:24:58

+0

@bummi,感謝這個代碼示例,我會在我的項目中嘗試這個。 – 2013-04-30 02:44:06