一位同事今天来到我这里,但是代码在Windows XP上运行但在Windows 7上失败了<:p>
用户登录'SalesOrdersystem'
失败
我的phychic调试告诉我他正在对一个已关闭的数据库连接运行查询,或者他忘了打开。
从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),它试图打开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 - 考虑到现实的限制。
答案 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会在代码在释放后访问对象时通知您。
显然,您无法使用该设置,但在运行测试套件时将其打开,此类错误将被刷新为开放视野。
答案 2 :(得分:0)
为什么编码器正在使用可能已被释放的TADOConnection对象?为什么不让线程创建自己的连接?这将允许线程控制连接的生命周期。