Определить, когда кто-то использует мое TADOConnection после того, как оно было освобождено? - PullRequest
0 голосов
/ 26 августа 2011

Коллега пришла ко мне сегодня с ошибкой с кодом, который работал в Windows XP, но не работает в Windows 7:

Пользователь не смог войти в систему 'SalesOrdersystem'

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

Начиная с ADO2.6, в Windows Vista значение по умолчанию PersistSecurityInfo в строке подключения False, а не True.

До Windows Vista строка подключения, такая как:

Data Source=deathstar;User ID=SalesOrderSystem;Password=password1

, сохраняла пароль в строке подключения после открытия подключения, что делает его эквивалентным:

Data Source=deathstar;User ID=SalesOrderSystem;
      Password=password1;PersistSecurityInfo=true

Начиная с Windows Vista, пароль по умолчанию удаляется из свойства ConnectionString соединения:

Data Source=deathstar;User ID=SalesOrderSystem

, что эквивалентно

Data Source=deathstar;User ID=SalesOrderSystem;
      Password=password1;PersistSecurityInfo=false

, который я зналмой коллега испытывал такое поведение при удалении пароля.И затем, пока соединение закрыто, он пытается открыть запрос (т.е. ADOQuery.Open), который без промедления пытается открыть соединение.Но без пароля, сохраненного в строке подключения, он получает свою первоначальную ошибку

Возник вопрос: «Почему вы используете соединение, не открывая его первым?»

Мы отследили егов (многопоточный код), где он использовал соединение, которое впоследствии было освобождено:

псевдокод:

customer := TCustomer.Create(ADOConnection)
ADOConnection.Free;
customer.RefreshFromDatabase;

вместо

customer := TCustomer.Create(DataModule.ADOConnection);
customer.RefreshFromDatabase;

В шутку я предложил, чтобы он мог замаскировать ошибку и оставить потенциальный сбой, изменив строку подключения, включив в нее PersistSecurityInfo=True:

connectionString := ...+
    ';PersistSecurityInfo=True';

Какой онdid.


У нас есть некоторый библиотечный код, который внутренне использует объект ADOConnection.я бы полюбил , чтобы иметь возможность изменить свой код с:

destructor TAsyncFill.Destroy; 
begin
   ...
   FreeAndNil(FADOConnection)
end;

на

destructor TAsyncFill.Destroy; 
begin
   ...
   FADOConnection.Close;
   FADOConnection.ConnectionString := 'This connection object has been freed. Why are you using it?';
   FreeAndNil(FADOConnection);
end;

Но я уверен это введетошибки, когда вещи случались работали.

Я имею в виду некое подобие замыкания, где я могу внедрить обработчик OnConnect в объект подключения:

destructor Destroy; 
begin
   ...
   FADOConnection.Close;
   FADOConnection.BeforeConnect := { 
       OutputDebugString('You''re using a connection that''s been freed!'); 
       Windows.Beep(1000, 60000) };
   FreeAndNil(FADOConnection);
end;

Но в Delphi нет анонимных обработчиков событий.

Может кто-нибудь придумать способ предупредить людей, когда они используют объект после его освобождения?


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

Ответы [ 3 ]

2 голосов
/ 26 августа 2011

Поскольку вы «FreeAndNil» используете AdoConnection, я предполагаю, что вы сами создаете его экземпляр.В этом случае вы можете получить собственный TMyAdoConnection и создать его экземпляр.Вам даже не нужно давать ему другое имя класса, если вы используете подход «перехватчик»:

type
  TAdoConnection = class(AdoDb.TAdoConnection)
  end;

Затем переопределите защищенный метод DoConnect.Несмотря на название, это не просто метод для запуска события OnConnect.Это на самом деле открывает соединение.Существует аналогичный метод DoDisconnect, который фактически закрывает соединение.

В этих двух переопределенных методах, плюс переопределения Create и Destroy, вы можете написать простой механизм обнаружения, когда Opens и Close не совпадают сСоздает и уничтожает.

Если у вас есть один экземпляр AdoConnection, вы можете просто отслеживать вещи в паре глобальных переменных.В противном случае вам, возможно, придется написать небольшой реестр, где вы будете отслеживать материал для каждого экземпляра.Будет трудно, хотя попытаться найти «Self» в этом реестре, если экземпляр был освобожден и установлен в ноль.Поэтому вам, возможно, придется на время отказаться от FreeAndNil и перекодировать любой if Assigned(FAdoConnection), чтобы обнаружить, что экземпляр все еще необходимо создать, с чем-то другим.

Предупреждение : Это основанона TAdoConnection в Delphi 6. У меня нет компонентов Ado, установленных в Delphi 5 на данный момент.Поэтому вам придется проверить, что DoConnect и DoDiscoonect присутствуют и являются виртуальными в D5.

1 голос
/ 26 августа 2011

FastMM с полной отладкой уведомит вас, когда ваш код получит доступ к объекту после его освобождения.

enter image description here

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

0 голосов
/ 26 августа 2011

Почему кодер использует объект TADOConnection, который, возможно, уже был освобожден?Почему бы потоку не создать свое собственное соединение?Это позволило бы потоку контролировать жизненный цикл соединения.

...