Вопрос

У меня есть сервер с этими кодами:

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?

Спасибо за ответы друзей.

Итак, это истинный способ сделать разные соединения для разных потоков?

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;
Это было полезно?

Решение

Ваш второй фрагмент кода не правильный. Вы перезаписываете новое соединение с Global Connect, когда вы должны копировать строку подключения. Вы также освобождаете эту глобальную, что, вероятно, вызвало проблемы для остальной части вашего приложения. Что-то вроде этого, в зависимости от деталей вашего класса TSCLConnection:

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 И иметь фабричный метод, который возвращает новое соединение с базой данных. Это дает мне пул резьбы, в который я кормит задачи, поэтому моя конкретная задача связана с существующей поток при его выполнении, но поток довольно долгожил. Код, который мне пришлось написать, чтобы получить это очень маленький (я использую 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;

Вам нужно будет сделать что-то похожее, если вы напишите свой собственный пул или соединительный пул.

Другие советы

Каждый доступа к потоке DB должен иметь собственное соединение, вы не можете поделиться соединением БД между несколькими потоками. Мероприятие Onexecute вызывается в контексте потока, соответствующей запрашивающему клиенту, поэтому каждый раз, когда он вызывается, он выполняется внутри рабочего потока, и такая нить должна иметь собственный соединение БД.

Если вы не хотите устанавливать новое соединение для каждого рабочего нити; Один вариант может быть, вы посвятите одну нить для соединения БД, и делегируйте все операции БД на этот поток, например, другие потоки могут отправлять свои данные вставки SQL в очередь в этой резьбе DB, а тема DB выполняет их по-одному, используя одно соединение БД. Конечно, если вы возьмете этот подход, вся нагрузка БД будет в одной поток, и если у вас так много операций БД, то сама резьба БД может быть узким местом для производительности! Более того, принимает этот подход, казни запросов будут асинхронными, за исключением того, что вы используете технику синхронизации всякий раз, когда каждая из ваших потоков просит потоку БД выполнить запрос DB для них.

Также примите обратите внимание, что если ваши компоненты доступа DB ADO ADO, то вам нужно позвонить в CoinItialize и регистризируйте, потому что Relphi Runtime только делает это для основного потока, а не другие потоки, которые вам создаются.

Я бы использовал бассейн соединения для соединений базы данных. Каждый поток затем запрашивает только соединение от пула при необходимости (который может блокировать, если в настоящее время нет бесплатных подключений в пуле), а затем использует и, наконец, возвращает его в пул. У бассейна есть то преимущество, что требуется меньше соединений, чем есть одновременные потоки, а соединения уже присутствуют при необходимости.

И да и нет. Вы можете получить доступ к одной таблице из разных потоков, но вам нужен экземпляр TSCLConnection на тему, чтобы сделать так безопасно.

Обновлять

Расположение другое соединение для каждого потока в порядке. Это то, что большинству веб-страний также выполняют все время (Server Signation Scripting с использованием ASP, PHP или ... означает, что меньшее количество выполнения, и, таким образом, соединения обычно не выживают до следующего запроса и должны быть восстановлены).

Если вы беспокоитесь о накладных расходах, вы можете рассмотреть возможность использования одного соединения, такого как VCDLEVEловы предлагает. Вам придется обеспечить, чтобы любые переменные и поля участников, используемые этой «соединительной нитью», которые изменяются другими потоками (например, элемент поля, получающего SQL, который будет выполнен), должен быть защищен каким-то образом синхронизации механизма синхронизации Отказ

То же самое относится и к пулу соединения, как предложено Mjustin, хотя в этом случае пул соединения должен быть защищен механизмами синхронизации.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top