#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()
, чтобы пользователь мог видеть, что приложение занято попытками подключиться.