,我又将 ADOQuery 分别通 过三个不同的 ADOConnection 来连接数据库且不加锁也没有问题。看来我是找 到那个可恶的炸弹了,怎么拆了它?
排除炸弹
炸弹找到了,我该怎么拆它?是简单的做线程同步还是每个线程都是用一 个 ADOConnection?这下我再也不敢蛮干了,我得好好看看这方面的资料,在 Delphi 帮助
文档,《Using the main VCL thread》我找到了下面一段话: …… Data access components are thread-safe as long as each thread has its own database session component. The one exception to this is when you are using Access drivers. Access drivers are built using the Microsoft ADO library, which is not thread-safe. ….. 同样在 Delphi 的帮助
文档《Managing multiple sessions》中给我明确的建 议: …… If you create a single application that uses multiple threads to perform database operations, you must create one additional session for each thread. ….. 喔找到了:ADO 控件是线程不安全的,所以如果你的程序是使用多线程访问数 据库的话你应该确保每个线程都有自己的会话。 事实上在另外一本书《
Delphi 4 编程技术内幕》一书在谈到线程安全数据库访 问也有相同的建议,不过台湾李维先生在他的《Delphi 5.X ADO/MTS/COM+高级 程序设计篇》却说,如果你的程序不是连接多个数据库的话,最好同一数据库 使用一个连接,不要使用多个连接。怎么办?谁对谁错?为什么要使用一个连 接呢?这主要是从服务器来考虑,因为数据库服务器需要为每个连接分配一定 的资源并对其进行维护,连接数越多服务器方所耗的资源就越多,服务器的性 能也就越差,所以要尽可能的减少客户端的连接
数。好在我的程序是作为服务 器程序增加一些连接对数据库服务器的影响不会很大,现在我可以重新设置我 的数据库访问结构模型了
③ADOQuery2
ADOConnection2
②ADOQuery3 ADOConnection1
数据库: Table1
图三
我增加了一个 ADOConnection 以保证每个线程都有一个自己连接(会话),从而 避免出现资源冲突,我的
问题是不是解决了呢?是的,这个问题已经解决了, 将我的程序与数据库放在同一台机器上运行没有问题,但是当程序与数据库服 务器不在同一台机器上运行时会出现一个新的问题。
[DBNMPNTW]ConnectionWrite(writeFile())错误
这个错误不是多线程引起的,而是 Micrsoft 自己的一个问题,产生该问 题的原因可能是因为
网络异常而引起的,可以通过 SQLServer 客户端的默认的 网络协议 named pipes network propocol 改为 TCP/IP Sockets,具体做法请 参考 Micrsoft 技术支持网站的《Microsoft Knowledge Base Article Q178040》
总结 由于 ADO 控件的线程不安全性(事实上这种不安全性是来自 Micrsoft ADO Library,所以在其它开发工具中也存在同样的问题)因此在使用多线程 ADO 编 程时应该注意一下问题:
第一:要保证每个线程都拥有自己的会话。 第二:作为客户端程序应该尽可能的减少与数据库库服务器的连接数。 第三:在退出线程之前确保释放所有的资源。
参考文献: 1、李维《Delphi 5.X ADO/MTS/COM+高级程序
设计篇》 机械工业出版社 2000。 2、Charlie Calvert《Delphi 4 编程技术内幕》潇湘
工作室 译 机械工业出版 社 1999。