multithreading - 在 OnExecute 事件中使用数据库 (Indy)

标签 multithreading delphi indy dbconnection

我有一个带有这些代码的服务器:

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;

在多个线程中访问一张表是否有问题?以及在 Onexecute 事件中使用什么是危险的?

谢谢 friend 的回复。

那么,为不同的线程建立不同的连接是正确的方法吗?

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;

最佳答案

您的第二个代码片段不正确。当您应该复制连接字符串时,您正在用全局连接覆盖新连接。您还将释放该全局变量,这可能会给您的应用程序的其余部分带来问题。像这样,取决于你的 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;
  ...

如果你想拥有一个数据库连接池,那是相当棘手的,因为连接通常是特定于线程的——你需要每个线程一个,你不能在线程之间传递它们。因此,您最终需要编写大量代码来支持它。

我现在使用 OmniThreadLibrary并有一个返回新数据库连接的工厂方法。这为我提供了一个线程池,我将任务输入其中,因此我的特定任务在执行时绑定(bind)到现有线程,但该线程的生命周期相当长。我必须为此编写的代码非常小(我使用的是 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;

如果您编写自己的线程或连接池,则需要做类似的事情。

关于multithreading - 在 OnExecute 事件中使用数据库 (Indy),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3537205/

相关文章:

delphi - 如何使用泛型处理普通动态数组?

Delphi - Indy - 保存 GMail 草稿

apache - Delphi 7/Indy 9 应用程序未通过 SSL 连接到 Apache

string - BobJenkinsHash 函数的结果可以为负数吗?

Delphi ADO + 书签

c++ - 我可以在我的 VCL 客户端-服务器应用程序中使用端口 80 吗?

java - ThreadPoolExecutor 没有执行所有任务

java - 如何计算多个线程完成执行的总时间?

c# - .NET Monitor 何时进入内核模式?

multithreading - 线程 : Why must all user threads be mapped to a kernel thread?