一位同事今天来找我,代码在 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';
他做到了。
我们有一些在内部使用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 没有匿名事件处理程序。
任何人都可以想出一种方法来提醒人们在释放对象后使用它吗?
注意:我知道我的要求不支持。考虑到现实的局限性,我正在寻求最佳黑客的想法。