Соединение TADOC с потоком SQL Server с Delphi

#sql #multithreading #delphi #adoconnection

Вопрос:

Я работаю над проектом, и мне нужно подумать о чрезвычайных ситуациях.

Основная проблема заключается в том, как проверить, подключена ли база данных (объект circle = красный или зеленый)?

BeforeConnect , AfterDisconnect , у них нет хорошего ответа.

Внутренний тип:

Создать Соединение:

 procedure TForm1.Button1Click(Sender: TObject);
var
  s : String;
begin
  ADOConnectionSQL := TADOConnection.Create(nil);
  ADOConnectionSQL.LoginPrompt := false;
  with ADOSQL do
  begin
    s := 'Provider=SQLNCLI11.1;' 
    'Persist Security Info=False;' 
    'User ID=' Edit1.Text ';' 
    'Initial Catalog=' Edit2.Text ';' 
    'Data Source=' Edit3.Text ';' 
    'Initial File Name="";' 
    'Server SPN="";' 
    'password="' Edit4.Text '"';
    ADOConnectionSQL.ConnectionString := s;
  end;
  ADOConnectionSQL.BeforeConnect := SQLConnected;
  ADOConnectionSQL.AfterDisconnect := SQLDisconnected;
end;
 

Попробуйте подключиться:

 procedure TForm1.Button2Click(Sender: TObject);
var
  Thread : TThread;
begin
  Thread := TThread.CreateAnonymousThread(
    procedure
    begin
      TThread.Synchronize(TThread.CurrentThread,
      procedure
        begin
        try
          ADOConnectionSQL.Connected := True;
          ADOConnectionSQL.Open;
        except
          on E: Exception do
          begin
            ShowMessage('Exception message = ' E.Message);
          end;
        end;
        ADOQuerySQL := TADOQuery.Create(nil);
      end);
    end);
  Thread.OnTerminate := FinishConnected;
  Thread.Start;
end;
 

Зеленый или Красный:

 procedure TForm1.SQLConnected(Sender: TObject);
begin
  Circle1.Fill.Color := $FF00FF00;
end;

procedure TForm1.SQLDisconnected(Sender: TObject);
begin
  Circle1.Fill.Color := $FFFF0000;
end;
 

Готово подключено:

 procedure TForm1.FinishConnected(Sender: TObject);
begin
  if TThread(Sender).FatalException <> nil then
  begin
    // something went wrong
    ShowMessage ('Failure to connection');
    //Exit;
  end;
end;
 

Когда SQL-сервер подключен, я хотел бы видеть зеленый круг. Когда соединение с сервером отключается, круг должен быть красным.

Ответ №1:

Вы создаете и открываете соединение ADO в контексте основного потока пользовательского интерфейса, а не в контексте рабочего потока. Таким образом, ваш рабочий поток в основном бесполезен. Вы могли бы просто использовать TThread.ForceQueue() вместо этого, чтобы получить тот же эффект.

ADO использует технологию COM внутри, поэтому вы все равно не сможете использовать ее через границы потоков. Если вы хотите использовать ADO в потоке, предоставьте потоку собственное соединение ADO и объекты запроса. Выполняйте всю свою работу с SQL в контексте потока и при необходимости синхронизируйте обновления статуса с основным потоком пользовательского интерфейса.

Кроме того, вам необходимо инициализировать библиотеку COM в рабочем потоке, прежде чем она сможет работать с ADO.

Попробуйте вместо этого что-нибудь более похожее:

 procedure TForm1.Button1Click(Sender: TObject);
var
  Thread : TThread;
  ConnStr: string;
begin
  ConnStr := 'Provider=SQLNCLI11.1;' 
    'Persist Security Info=False;' 
    'User ID=' Edit1.Text ';' 
    'Initial Catalog=' Edit2.Text ';' 
    'Data Source=' Edit3.Text ';' 
    'Initial File Name="";' 
    'Server SPN="";' 
    'password="' Edit4.Text '"';

  Thread := TThread.CreateAnonymousThread(
    procedure
    var
      ADOConnectionSQL: TADOConnection;
      ADOQuerySQL: TADOQuery;
    begin
      CoInitialize(nil);
      try
        ADOConnectionSQL := TADOConnection.Create(nil);
        try
          ADOConnectionSQL.LoginPrompt := False;
          ADOConnectionSQL.ConnectionString := ConnStr;

          ADOConnectionSQL.Open;

          TThread.Queue(nil,
            procedure
            begin
              Circle1.Fill.Color := TAlphaColorRec.Green;
            end
          );

          ADOQuerySQL := TADOQuery.Create(nil);
          try
            ADOQuerySQL.Connection := ADOConnectionSQL;
            // use ADOQuerySQL as needed...
          finally
            ADOQuerySQL.Free;
          end;
        finally
          ADOConnectionSQL.Free;
        end;
      finally
        CoUninitialize;
      end;
    end);
  Thread.OnTerminate := SQLFinished;
  Thread.Start;
end;

procedure TForm1.SQLFinished(Sender: TObject);
begin
  Circle1.Fill.Color := TAlphaColorRec.Red;
  if TThread(Sender).FatalException <> nil then
  begin
    // something went wrong
    ShowMessage('Failure! '   Exception(TThread(Sender).FatalException).Message);
  end;
end;
 

Комментарии:

1. Большое вам спасибо, я старался, и это работает. Я считаю, что я не был на 100% ясен. Когда я пытаюсь подключиться к базе данных и IP-адрес неверен, программное обеспечение будет заблокировано до завершения тайм-аута (вы это исправили), но я хотел бы, чтобы круг был зеленым все время, пока доступно соединение, и красным, когда оно отключается. Может быть, таймер, чтобы исправить это. У тебя есть какие-нибудь идеи?

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