В современных клиент-серверных приложениях, особенно работающих с базой данных и внешними сервисами, важно уметь эффективно использовать асинхронное программирование. Это позволяет избежать задержек и "зависаний" интерфейса в ожидании выполнения длительных операций. Рассмотрим примеры, когда разработчики сталкиваются с проблемой синхронных вызовов серверных методов в приложениях Datasnap и как можно решить эти задачи, чтобы достичь бесконечного ожидания.
Проблема
Разработчик сталкивается с необходимостью реализовации асинхронных вызовов методов на сервере в приложении Datasnap, где сервер связан с базой данных SQL и использует TCP-соединение с клиентом. Клиент выполняет HTTP POST запросы к REST-сервису, и важно, чтобы основной поток не ожидал выполнения этих операций.
Решение
Шаг 1: Понимание серверного метода
Серверный модуль DM1 содержит компоненты для работы с данными и запросами к SQL-серверу, а также компоненты для выполнения REST-запросов. В DM1 есть функция PostDataAsync, которая асинхронно выполняет HTTP POST запросы к REST-сервису и возвращает количество неудачных операций через коллбэк.
Шаг 2: Реализация асинхронного вызова с коллбэком
Пример серверного метода:
procedure TServerMethods1.postCustOrderHistAsync(CustomerID: String; callback: TDBXcallback);
var
jsonObject: TJSONObject;
CallbackValue: TJsonValue;
errors: Integer;
begin
// Выполнение операций с данными
errors := postCustOrderHist(CustomerID);
// Формирование JSON ответа
jsonObject := TJSONObject.Create;
jsonObject.AddPair(TJsonPair.Create('errors', errors.ToString));
// Вызов коллбэка
CallbackValue := callback.Execute(jsonObject);
end;
Шаг 3: Клиентский вызов
Клиент использует функцию postCustOrderHistAsync, передавая коллбэк, который отображает статус операции после её завершения.
procedure TMainForm.BtnPostOrderHistoryClick(Sender: TObject);
var
callback: TDBXCallback;
ServerMethods1Client: TServerMethods1Client;
begin
// Создание коллбэка
callback := TDSCallbackWithMethod.Create(
function(const Args: TJSONValue): TJSONValue
begin
// Обработка ответа сервера
if Args.GetValue<Integer>('errors') = 0 then
// Отображение уведомления об успехе
else
// Отображение уведомления об ошибке
end;
Result := TJsonTrue.Create;
end);
// Вызов серверного метода
ServerMethods1Client := TServerMethods1Client.Create(DMServerConnection.SQLConnection1.DBXConnection);
try
ServerMethods1Client.postCustOrderHistAsync(EditCustomerId.Text, callback);
finally
ServerMethods1Client.Free;
end;
end;
Шаг 4: Асинхронная отправка запросов
Проблемы, возникающие при одновременных вызовах, можно решить, разделив объекты соединения для каждого потока, чтобы избежать одновременного доступа к одному и тому же экземпляру DBXConnection.
function getNewSqlConnection(Owner: TComponent): TSQLConnection;
var
SqlConnectionLocal: TSQLConnection;
begin
SqlConnectionLocal := TSQLConnection.Create(nil);
with SqlConnectionLocal do
begin
ConnectionString := Owner.ComponentByName('SQLConnection1').ConnectionString;
// Настройка остальных параметров
end;
Result := SqlConnectionLocal;
end;
procedure TMainForm.BtnPostOrderHistoryClick(Sender: TObject);
begin
TTask.Run(
procedure
var
ServerMethods1Client: TServerMethods1Client;
SqlConnectionLocal: TSQLConnection;
errors: Integer;
begin
SqlConnectionLocal := getNewSqlConnection(Self);
ServerMethods1Client := TServerMethods1Client.Create(SqlConnectionLocal.DBXConnection);
try
errors := ServerMethods1Client.postCustOrderHist(EditCustomerId.Text);
TThread.Synchronize(nil,
procedure
begin
if errors = 0 then
showNotification(StrSentSuccessfully)
else
showNotification(StrSendingFailed + '(' + errors.ToString + ' not sent)')
end);
finally
ServerMethods1Client.Free;
SqlConnectionLocal.Free;
end;
end);
end;
Шаг 5: Использование TThread.Queue для безопасности
Для безопасной обработки коллбэков можно использовать TThread.Queue.
Вывод
При правильной реализации асинхронных вызовов в Datasnap, клиент не будет ожидать окончания серверных операций, и сможет продолжать свою работу, получая результаты выполнения через коллбэки. При этом, важно обеспечить корректное управление ресурсами и изолировать данные для каждого асинхронного запроса.
Асинхронное программирование в Datasnap позволяет избежать блокировки основного потока клиента при выполнении длительных операций на сервере, используя коллбэки и управление потоками.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.