检测有人在释放后使用我的TADOConnection?

时间:2011-08-26 15:54:25

标签: delphi ado delphi-5

一位同事今天来到我这里,但是代码在Windows XP上运行但在Windows 7上失败了<:p>

  

用户登录'SalesOrdersystem'

失败

我的phychic调试告诉我他正在对一个已关闭的数据库连接运行查询,或者他忘了打开。

  

从ADO2.6开始,在Windows Vista中,连接字符串中的默认值PersistSecurityInfoFalse,而不是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),它试图打开Connection。但是如果没有在连接字符串中保存密码,他就会得到原始错误

问题变成了,“你为什么不先打开它就使用连接?”

我们追溯到(多线程代码),他正在使用后来被释放的连接:

伪码:

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

而不是

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

在开玩笑中,我建议他可以屏蔽错误,并通过更改连接字符串以包含PersistSecurityInfo=True来保留潜在的崩溃:

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

他做了什么。


我们有一些内部使用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没有匿名事件处理程序。

任何人都可以想到一种方法,可以在人们被释放后使用对象时提醒他们吗?


注意:我知道我不会支持我的要求。 i'm asking for ideas for the best possible hacks - 考虑到现实的限制。

3 个答案:

答案 0 :(得分:2)

由于你是“FreeAndNil”你的AdoConnection,我假设你自己也在实例化它。在这种情况下,您可以做的是派生自己的TMyAdoConnection并实例化它。如果你采用“拦截器”方法,你甚至不必给它另一个类名:

type
  TAdoConnection = class(AdoDb.TAdoConnection)
  end;

然后,覆盖受保护的DoConnect方法。尽管它的名称不是“仅仅”一种触发OnConnect事件的方法。它确实打开了一个连接。还有一个类似的DoDisconnect方法,它实际上关闭了连接。

在这两个重写的方法中,加上Create和Destroy的覆盖,你可以为Opens和Closes与Creates和Destroys不匹配时编写一个简单的检测机制。

如果你有一个AdoConnection实例,你可以跟踪几个全局变量中的事物。否则,您可能需要编写一个小型注册表,以便跟踪每个实例的内容。如果实例已被释放并设置为nil,那么试图在该注册表中找到“Self”会很难。因此,您可能不得不暂时放弃FreeAndNil并重新编码任何if Assigned(FAdoConnection)以检测是否仍需要使用其他内容创建实例。

警告:这是基于Delphi 6中的TAdoConnection。目前我没有在Delphi 5中安装Ado组件。因此,您必须检查DoConnect和DoDiscoonect是否存在以及D5中的虚拟。

答案 1 :(得分:1)

具有完全调试功能的FastMM会在代码在释放后访问对象时通知您。

enter image description here

显然,您无法使用该设置,但在运行测试套件时将其打开,此类错误将被刷新为开放视野。

答案 2 :(得分:0)

为什么编码器正在使用可能已被释放的TADOConnection对象?为什么不让线程创建自己的连接?这将允许线程控制连接的生命周期。