Microsoft AlwaysOn отказоустойчивое решение и Delphi
Я пытаюсь заставить приложение Delphi работать с решением AlwaysOn. Я нашел в Google, что я должен использовать MultiSubnetFailover=True
в строке подключения.
Приложение скомпилировано в Delphi XE3 и использует TADOConnection
,
Если я использую Provider=SQLOLEDB
в строке подключения приложение запускается, но выглядит MultiSubnetFailover=True
не имеет никакого эффекта
Если я использую Provider=SQLNCLI11
(Я обнаружил в Google, что OLEDB не поддерживает решение AlwaysOn, и мне приходится использовать собственный клиент SQL) Я получаю недопустимый атрибут при попытке открыть соединение.
Строка подключения:
Provider=SQLOLEDB.1;Password="password here";Persist Security Info=True;User ID=sa;Initial Catalog="DB here";Data Source="SQL Instance here";MultiSubnetFailover=True
Нужно ли переходить на более новую версию в Delphi, чтобы использовать это решение для восстановления после сбоя, или я что-то упускаю в строке подключения?
1 ответ
В настоящее время я использую XE2 с SQL Server AlwaysOn. Если вы прочитаете документацию, то увидите, что события устойчивости AlwaysOn приведут к сбою подключения к базе данных, и вам нужно будет инициировать новое.
Если приложение SqlClient подключено к базе данных AlwaysOn, при которой происходит сбой, исходное соединение разрывается, и приложение должно открыть новое соединение, чтобы продолжить работу после отработки отказа.
Я справился с этим с помощью простого способа переопределения компонента TAdoQuery моей собственной версией, которая повторяет соединение после сбоя соединения. Это может быть неправильный способ сделать это, но это, безусловно, работает. Он переопределяет методы, вызываемые для открытия (если запрос возвращает набор результатов) или выполняет SQL (в противном случае), и в случае сбоя из-за потери соединения повторяется попытка (но только один раз). Я тщательно проверил это в отношении переключателей AlwaysOn, и он надежно работает для нашей конфигурации. Он также будет реагировать на любые другие события потери соединения и, следовательно, будет иметь дело с некоторыми другими причинами сбоя запросов. Если вы используете компонент, отличный от TAdoQuery, вам необходимо создать аналогичные переопределения для этого компонента.
Возможно, с этим можно справиться и другими способами, но я перестал искать альтернативы, как только нашел то, что сработало. Возможно, вы захотите привести в порядок утверждение использования, поскольку оно явно включает в себя некоторые вещи, которые не нужны. (Просто глядя на этот код, я хочу уйти и реорганизовать дублирование кода)
unit sptADOQuery;
interface
uses
Windows, Messages, SysUtils, Classes, Db, ADODB;
type
TsptADOQuery = class(TADOQuery)
protected
procedure SetActive(Value: Boolean); override;
public
function ExecSQL: Integer; // static override
published
end;
procedure Register;
implementation
uses ComObj;
procedure Register;
begin
RegisterComponents('dbGo', [TsptADOQuery]);
end;
procedure TsptADOQuery.SetActive(Value: Boolean);
begin
try
inherited SetActive(Value);
except
on e: EOleException do
begin
if (EOleException(e).ErrorCode = HRESULT($80004005)) then
begin
if Assigned(Connection) then
begin
Connection.Close;
Connection.Open;
end;
inherited SetActive(Value); // try again
end
else raise;
end
else raise;
end;
end;
function TsptADOQuery.ExecSQL: Integer;
begin
try
Result := inherited ExecSQL;
except
on e: EOleException do
begin
if (EOleException(e).ErrorCode = HRESULT($80004005)) then
begin
if Assigned(Connection) then
begin
Connection.Close;
Connection.Open;
end;
Result := inherited ExecSQL; // try again
end
else raise;
end
else raise;
end;
end;
end.