现在我用一个ADOConnection 连接到MSSQL,在FORM上放有多个Table、DataSource、DBGrid.并一对一地关联好,现在我想要实现在多线程的方法同时打开这几个Table.代码如下:QueryThread= class(TThread)
  private
    FSP:TAdoStoredproc;
    PName:string;
    FSPException:Exception;
    procedure FSPError;
  protected
    procedure Execute; override;
  public
   Constructor Create(FP:TAdoStoredproc;FName:String);virtual;
   //Destructor Destroy;override;
 end;
implementation{$R *.dfm}
var
 Nextnumber:integer=0;
 Doneflags:integer=0;
 Hsem:Thandle=0;
Constructor QueryThread.Create(FP:TADOStoredproc;FName:String);
begin
  inherited create(False);
  FreeOnTerminate:=True;
  FSP:=FP;
  Pname:=Fname;
  resume;
end;procedure QueryThread.Execute;
var
 I:integer;
 WaitReturn:DWORD;
begin
 Onterminate:=form1.ThreadsDone;
 WaitReturn:=Waitforsingleobject(Hsem,Infinite);
 if WaitReturn=WAIT_OBJECT_0 then
 begin
  with FSP do
   begin
     Close;
     TableName:=Trim(PName);
   try
     Prepared:=true;
     open;
   except
     FSPException:=Exceptobject as exception;
     synchronize(FSPError);
   end;
  end;
 end;
 ReleaseSemaphore(hSem,1,nil);
end;
procedure QueryThread.FSPError;
begin
  application.ShowException(FSPException);
end;procedure TForm1.ThreadsDone(Sender:Tobject);  //一点同步的代码,但没有的
var
 i:integer;
begin
  inc (Doneflags);
  if doneflags=2 then
    closehandle(hsem);
end;
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
  Hsem:=createSemaphore(nil,1,1,nil);
  Querythread.Create(T1,'Test');
  Querythread.Create(T2,'Test');
  QueryThread.Create(T3,'test');
end;
为什么会有错误的呢,请各位多多介绍下在数据库多线程应用。

解决方案 »

  1.   

    我对你的代码进行了简化和修改, 可以正常运行了, 希望你能从中得到帮助, 解决你的问题.unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, DB, ADODB;type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementationuses Unit2;{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
    var
      T1, T2, T3: TADOStoredProc;
    begin
      T1:= TADOStoredProc.Create(self);
      T2:= TADOStoredProc.Create(self);
      T3:= TADOStoredProc.Create(self);
      TQuerythread.Create(T1,'Test');
      TQuerythread.Create(T2,'Test');
      TQueryThread.Create(T3,'Test');
    end;end.--------------------------------------------------
    unit Unit2;interfaceuses
      Classes, ADODB;type
      TQueryThread = class(TThread)
      private
        FSP:TAdoStoredproc;
        PName:string;
        procedure doit;
      protected
        procedure Execute; override;
      public
        Constructor Create(FP:TAdoStoredproc;FName:String);virtual;
      end;implementationConstructor TQueryThread.Create(FP:TADOStoredproc;FName:String);
    begin
      inherited create(False);
      FreeOnTerminate:=True;
      FSP:=FP;
      Pname:=Fname;
      resume;
    end;procedure TQueryThread.Execute;
    begin
      synchronize(doit);
    end;procedure TQueryThread.doit;
    begin
      with FSP do
       begin
         ConnectionString:= 'Provider=MSDASQL.1;Persist Security Info=False;User ID=test01;Data Source=MS Access Database;Initial Catalog=C:\我的文档\test01';
         ProcedureName:=PName;
         Prepared:=true;
         open;
       end;
    end;end.
    给出以下改进建议:1. 最好在声明线程类时, 将其名字前加上T, 比如本例的TQueryThread, 否则写起来很不方便.
    2. 线程中凡是涉及到窗体的部分都要同步, 比如TQueryThread.doit部分进行的操作就要在TQueryThread.Execute中用synchronize(doit)调用.
    3. Unit1中使用T1, T2, T3时, 要先声明并实例化, 否则会出现错误.
    4. 再有一点我不太明白, 你要打开Tabel为什么要用TADOStoredproc? TADOStoredproc根本没有TableName属性呀? 可以考虑使用TADOCommand, 通过设置其CommandType和CommandText可以对Table, Query, StoredProc等各种类型进行操作.不知我是否解决了你的问题, 如还有疑问请将具体的错误提示信息写出来, 以便大家分析.
      

  2.   

    数据库的多线程处理与其它方面的多线程处理不同之处就在于, 多个线程同时"重复"操作一个数据库是不行的.解决办法就是在每个线程访问时都产生唯一的DatabaseName. 本来数据库名为test, 多个线程访问它时要各自产生一个名字, 像test01, test02... 
    但问题是Delphi又是如何知道它们都代表test而不是多个互不相干的数据库呢? 这就需要TSession帮忙. 通过设置TDatabass和TDataSet的SessionName属性, 以及唯一产生SessionName(就像DatabaseName一样)就可以实现数据库的多线程处理. 
    请看这样一段代码:UniqueNumber := GetUniqueNumber;Session.SessionName := Format('%s%x', [Session.Name, UniqueNumber]);
    Database.DatabaseName := Format('%s%x', [Database.Name, UniqueNumber]);
    Database.SessionName := Session.SessionName;Query.SessionName := Session.SessionName;
    Query.DatabaseName := Database.DatabaseName;
    Query.Open;
    所以除非你使用多线程访问不同的数据库, 否则就要在线程中对Session和Database进行唯一化.
      

  3.   

    感谢 zousoft的回答,我现在按你的方法解决了,前面我的代码原来是以TADOStoredProc1来设计的,但我考虑到用Storedproc1的代码更长,我草草地改为TADOtable.好现在发分!!!