Delphi多线程下的ADO编程

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情
 

Delphi多线程下的ADO编程

 

 

前言:

几个月前接到一个任务:将一后台程序访问数据库的方式从BDE改为ADO,原因是由于业务量的增加,通过BDE不论是向数据库写入数据还是从数据库中读出数据的速度都变得无法忍受,大家都知道ADO在数据库访问速度方面比BDE要快的多了(我写了一个测试程序使用ADO比使用BDE快了近100!)。这个任务还不简单嘛,只要将BDE的控件更换成ADO的再修改一些代码不就搞定了!我当时确实是这么想的,而且用了不到一个小时就搞定,测试运行一段没问题,大功告成了,我想。谁知道一个恶梦就此开始,我的愚昧无知使我在程序中埋下了一个超级炸弹,它的威力不次于9.11撞击世贸大厦的两架客机,整个系统被它无情的催跨。程序在运行很长一段时间候捕获到一系列的异常:

OLE error 800A0E7F

Access violation at address 00135770. Write of address 005D8B78

Access violation at address 00178EC6. Read of address FFFFFFFF

Access violation at address 1F499BDD in module 'msado15.dll'. Read of address 0000000C

…….

接下来我们的系统就像世贸大厦一下悲壮的倒下了。

 

为什么?

       为什么?程序在为改动之前使用BDE运行得好好的,我并没有更改程序的结构啊?我十分的迷惑,当然要想解决问题一切都得从错误代码开始。

   OLE error 800A0E7F:什么咚咚来的?它什么意思?什么原因引起的?我找了半天也没有在我的系统里找到它的说明,好在现在网络发达,也许有人遇到跟我一样的问题吧,于是我用OLE error 800A0E7F作为关键字搜了一下,嘿嘿,果真被我找到了:

>0x800A0E7F Operation cannot be performed while executing
> asynchronously.

异步执行时操作不能被执行(完成),还是不太清楚错误的原因,于是我在一个网站发布了帖子求助,一些人告诉我ADO线程不安全,需要线程同步,事实上我的程序做了同步,而且针对不同的应用使用了多个ADOConnection,我想我应该自己动手来好好研究一下这个问题了,它很意思。接下来我该好好分析我的程序并做一系列的测试来找到那个炸弹。

 

找出炸弹

 

    在我的程序里所有访问数据库都是通过一个DataModule单元TDataModule1类提供的接口来完成,共有三个线程使用到了TDataModule1的对象DataModule1DataModule1

Delphi 的异步方法TTask.Run 上述代码里面:TThread.Synchronize 是同步,对 Run 里面的执行在线程里面的代码,做一个和主线程的同步。这里所谓的“同步”,是指 TThread.Synchronize 里面的代码,是丢给主线程去执行的,并且要等到主线程执行完里面的代码,TThread.Synchronize 才结束返回。这样的代码写法,有一定的好处。有点类似之前有些第三方控件封装的线程对象,一个 Run 事件里面,放需要线程执行的代码。换句话说,如果 Run 的括号里的方法要执行完,Run 才返回,是同步方法。 阅读详情

相关推荐

Delphi 5.0初学者编程范例教程

Delphi是由Borland公司开发的一种集成开发环境(IDE),支持多种操作系统平台。它使用的是一种基于Pascal语言的面向对象扩展——Object Pascal。Delphi独特的组件框架,VCL(Visual Component Library),极大地简化了Windows应用程序的开发过程。VCL(Visual Component Library)是Delphi中用于快速开发应用程序的一个图形化的组件库。它提供了一套丰富的预构建组件,使得开发者可以在构建用户界面时更加直观和高效。

weixin_42604188的博客 1105

Delphi使用ADO连接池(存储过程示例)

一个使用ADO连接池的示例,演示了TADOStoredProc动态参数的使用,带重连机制 =================== unit UnitDemo; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm2 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form2: TForm2; //数据库服务器 gDBServer: String = '127.0.0.1'; //数据库名称 gDBName: String = 'master'; //数据库用户名 gDBUser: String = 'sa'; //密码 gDBPass: String = '2001'; implementation {$R *.dfm} uses ADODB, UnitADOConnectionPool; const CreateSQL = 'create procedure TestMyPool (@type sysname) '#13#10+ 'as'#13#10+ 'select * from sysobjects where xtype=@type'#13#10+ 'return @@rowcount'; DeleteSQL = 'if Exists(select 1 from sysobjects where xtype=N''P'' and name=N''TestMyPool'')'#13#10+ ' drop procedure TestMyPool'; var gPoolMan: TADOConnPoolMan = Nil; procedure TForm2.Button1Click(Sender: TObject); var ADOObject:TADOConnPoolObject; ADOStoredProc:TADOStoredProc; Running :Integer; I: Integer; begin //取得一个存储过程资源(含一数据库有效连接) ADOObject := gPoolMan.CreateSP('TestMyPool'); if ADOObject = Nil then //取得资源失败 Exit; try ADOStoredProc := ADOObject.ExecObject as TADOStoredProc; Running := 2;//允许重试(两次)操作,以便在操作失败之后达到重连 while Running>0 do begin Dec(Running); if ADOObject.NeedRefresh then begin//判断是否有重连标志(比如数据库断开等,可能需要进行重连) if Not ADOObject.Reconnect then Exit; ADOObject.NeedRefresh := Not ADOStoredProc.Parameters.Refresh; if ADOObject.NeedRefresh then Exit; end; for I := 1(*Zero is the *Result* Parameter*) to ADOStoredProc.Parameters.Count - 1 do begin //========================= //传递参数 ADOStoredProc.Parameters.Items[I].Value := 'U'; //========================= end; if Running 0 then try //执行存储过程 ADOStoredProc.Open; //执行存储过程成功,退出循环进入后续的数据处理 break; except On E:Exception do begin //执行失败非程序级的异常通常有两种可能: //1.数据库连接断开 //2.自适合的参数传递当中可能存储过程已更新,参与不一致 //设置重连标志 ADOObject.NeedRefresh := True; //=================== //这里记录数据库操作失败日志 //=================== end; end; Exit; end; //========================== //从ADOStoredProc当中读取记录 ShowMessage(IntToStr(ADOStoredProc.Parameters.ParamByName('Result').Value)); //========================== //关闭存储对象的资源 ADOStoredProc.Close; finally //调用结束,释放资源 ADOObject.Free; end; end; procedure TForm2.FormCreate(Sender: TObject); var ADOConn:TADOConnection; begin (****************BEGIN*******************) (*注:仅为测试准备 *) //初始化测试环境 ADOConn := Nil; if Not TADOConnPoolMan.ConnectADO( gDBServer,gDBUser,gDBPass,gDBName,true,ADOConn) then Exit; try ADOConn.Execute(DeleteSQL); ADOConn.Execute(CreateSQL); finally try ADOConn.Close; except end; ADOConn.Free; end; (*****************END********************) //初始化连接池 gPoolMan := TADOConnPoolMan.Create(gDBServer,gDBUser,gDBPass,gDBName,true); end; procedure TForm2.FormDestroy(Sender: TObject); var ADOConn:TADOConnection; begin //释放连接池 if Assigned(gPoolMan) then gPoolMan.Free; (****************BEGIN*******************) (*注:仅为测试准备 *) //清理测试环境 ADOConn := Nil; if Not TADOConnPoolMan.ConnectADO( gDBServer,gDBUser,gDBPass,gDBName,true,ADOConn) then Exit; try ADOConn.Execute(DeleteSQL); finally try ADOConn.Close; except end; ADOConn.Free; end; (*****************END********************) end; end.

Delphi程序设计与开发手册:GUI设计、多线程数据库应用

Delphi作为一个高级语言开发环境,提供了对多线程的全面支持。Delphi中的TThread类是实现多线程的关键组件,它封装了线程的基本操作,使得开发者可以较为容易地进行多线程编程。TThread类实现了以下功能:简化线程的创建和启动流程。提供了挂起、恢复和终止线程的接口。允许线程访问所属组件的线程安全方法。支持线程间的事件通知机制。Delphi自1995年推出以来,一直是快速网络应用开发的首选工具之一。

weixin_42627459的博客 501

delphiXE多线程同步对象及异步执行.zip

本下载解决delphiXE在处理多线程时,如何对各线程进行管理、如何做到中途中断执行多线程时的线程安全,如何在多线程内部进行UI同步等等,还可看我的博文同步。

delphi 多线程 动态创建ADO

delphi多线程中动态连接ADO控件 异常:exception class EOleSysError with message '尚未调用CoInitialize' 如果是使用多线程的话那就在 Execute事件的开头加上 CoInitialize(nil); 结尾加上CoUninitialize() unit Unit1;interfaceuses Windows, Mes...

weixin_30872867的博客 593

【转】Delphi多线程学习(9):多线程数据库查询(ADO

原文:http://www.cnblogs.com/djcsch2001/articles/2382559.html ADO多线程数据库查询通常会出现3个问题: 1、CoInitialize 没有调用(CoInitialize was not called);所以,在使用任何dbGo对象前,必须手 调用CoInitialize和CoUninitialize。调用CoInitialize失败会产...

weixin_33953384的博客 271

Delphi多线程学习:多线程数据库查询(ADO

 ADO多线程数据库查询通常会出现3个问题:    1、CoInitialize 没有调用 (CoInitialize was not called);所以,在使用任何dbGo对象前,必须手 调用CoInitialize和CoUninitialize。调用CoInitialize失败会产生"CoInitialize was not called"例外。    2、画布不允许绘画 (Can

疯流人物 1311

AsyncCalls(异步调用函数)

AsyncCalls(异步调用函数),Delphi异步调用函数的单元和例子

Delphi进度条(多线程),美观不卡界面,简单开启,定位,结束

Delphi进度条(多线程),美观不卡界面,简单开启,定位,结束: 包目录(MyProgress): MyProgress.dcu //最终引用 MyProgressPackage.bpl //安装包 MyProgressPackage.bpi MyProgressPackage.dcp MyProgressPackage.lib 包安装(无需编译,直接安装): 将包目录(MyProgress)复制到目标安装目录 Delphi\菜单\Component\Install Packages\...选择包目录中的包文件 .\MyProgressPackage.bpl 添加路径: Delphi\菜单\Tools\Options\Environment Options\Delphi Optioins\Library\Library path: 添加包目录 在工程中单元中引用: uses MyProgress 功能列表: 1.开启进度(标题,消息,透明度(0-255),是否同步任务栏,是否有边框) procedure StartPro(aTitle,aMsg:String; AlphaValue:Integer=0; IsSyncTaskbar:Boolean=True; IsHasBorder:Boolean=True);//显示动画 2.给养进度(标题,,消息):保持或更新进度指示,不调用则保持StartPro时的状态 procedure FeedPro(aTitle:String; aMsg:String='正在处理中, 请等待...'); 3.关闭进度 procedure ClosePro;

delphi多线程调用dll

delphi多线程调用dll delphi多线程调用dll 有点复杂

Delphi多线程快速检测SQL连接源码解析

Delphi诞生于1995年,最初由Borland公司推出,并迅速成为市场上的主导RAD(Rapid Application Development)工具。其特点包括编译速度快、执行效率高以及易于学习和使用的语言特性。Delphi的VCL(Visual Component Library)提供了一套完备的组件库,使得开发者能够快速创建复杂的GUI(Graphical User Interface)应用程序。Delphi的并行编程库提供了丰富的API支持并行处理。

weixin_35238815的博客 991

Delphi的线程类

本文是没有写过delphi多线程,对delphi的线程类TThread不熟悉的人而写的,主要从 TThread的源代码入手.  Delphi多线程的实现专门封装了一个TThread类来实现,我们从Create函数入手来认识一下这个类,这里一般都是windows下的开发,所以先去掉linux环境的代码: constructor TThread.Create(CreateSuspended:

wozengcong的专栏 3034

Delphi实现传奇游戏服务器端代码解析

htmltable {th, td {th {pre {简介:传奇游戏服务器端Delphi代码展示了一系列游戏服务端开发中的关键技术和概念。Delphi的强大面向对象编程能力,使得它在游戏服务端开发中显得尤为重要。本代码关注了包括网络编程多线程数据库交互、数据结构与算法、安全性、通信协议、性能优化和错误处理等多个方面,为游戏服务器的核心功能提供支持。学习这些技能不仅可以掌握传奇服务器的实现,还能将其应用在更广泛的多人在线游戏服务端开发上。

weixin_35516273的博客 979

带着问题学习delphi

今天学习了基本的语法和线程,明天再学习下类,组件比较简单,活学活用吧。 unit Unit1; interface uses   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,   Dialogs, StdCtrls; type   T

224

delphi问题集(二)

====================================================== 注:重要!程序员如何有效的放松身心!下班后做什么? ====================================================== 问题1:在delphi中如何对变量赋值? 答:在delphi中使用的编程语言是基于pascal的面向对象语言,但是在

76
上一篇: 如何提高SQL SERVER的性能
weekendW
博客等级 码龄24年 1粉丝 2原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值