精华内容
下载资源
问答
  • 最近使用delphi开发软件中使用6个线程同时操作access数据库,反应经常无规律报错问题,分析可能是在多线程中操作ACCESS数据库存在问题.通过了一个多线程数据库测试程序,经过测试发现在多线程操作数据库,需要注意以下...
    最近使用delphi开发软件中使用6个线程同时操作access数据库,反应经常无规律报错问题,分析可能是在多线程中操作ACCESS数据库存在问题.通过写了一个多线程数据库测试程序,经过测试发现在多线程操作数据库,需要注意以下3点:
          1.操作ADO前必须使用 CoInitialize(nil) 和操作完成后使用CoUninitialize
          2.必须使用TADOQuery.Create(nil) 不能使用TADOQuery.Create(Self)或TADOQuery.Create(Application)
          3.所有线程TADOQuery不能使用同一TADOConnection进行连接,可以这样用 ADOQuery1.ConnectionString := ADOConnection1.ConnectionString;
       
          经过测试,在不注意以上3点情况下,线程执行10ms时,线程开到6时,就会引起内存地址报错了,如果注意以上3点线程可以开到60个线程.长时间运行稳定
          正确方法例如:
             CoInitialize(nil); //需要引用ActiveX
             ADOQuery1 := TADOQuery.Create(nil);
             try
                with ADOQuery1 do
                begin
                  Close;
                  ConnectionString := ADOConnection1.ConnectionString;
                  SQL.Text := 'select * from  t_captureimage';
                  Open;
                end;
             finally
                FreeAndNil(ADOQuery1);
                CoUninitialize;
             end;
    展开全文
  • Delphi拖延线程

    2018-01-09 09:12:07
    在有些情况下,事件触发特别频繁,但是我们不希望事件每次触发都执行他对应的功能而是在我们操作完毕后才执行功能。 比如:Edit1.OnChange事件对应了一...我了一个拖延线程: unit UntTaskDelay; interface uses

    在有些情况下,事件触发特别频繁,但是我们不希望事件每次触发都执行他对应的功能而是在我们操作完毕后才执行功能。

    比如:Edit1.OnChange事件对应了一个查询本地库的操作,当我们比较快速的输入时界面总是出现卡顿的现象,感觉很不爽。

    如何才能使程序在我们停止输入时才执行查询数据库操作呢?


    我写了一个拖延线程:

    unit UntTaskDelay;
    
    interface
    
    uses
      Windows, Classes;
    
    type
      TTaskDelay = class(TThread)
      private
        FStart: Cardinal;
        FOffSet: Cardinal;
        FHWND: HWND;
        FWM_START: Cardinal;
      protected
        procedure Execute; override;
      public
        constructor Create(cOffSet: Cardinal; MainHdl: HWND; wmStart: Cardinal);
        destructor Destroy; override;
        procedure Delay;
    
        property OffSet: Cardinal read FOffSet write FOffSet;
      end;
    
    var
      TaskDelay: TTaskDelay;
    
    implementation
    
    { TaskDelay }
    
    constructor TTaskDelay.Create(cOffSet: Cardinal; MainHdl: HWND; wmStart: Cardinal);
    begin
      FOffSet:= cOffSet;
      FStart:= GetTickCount + FOffSet;
    
      FHWND:= MainHdl;
    
      FWM_START:= wmStart;
    
      inherited Create(True);   
      FreeOnTerminate:= True;
    end;
    
    procedure TTaskDelay.Delay;
    begin
      FStart:= GetTickCount + FOffSet;
    end;
    
    destructor TTaskDelay.Destroy;
    begin
    
      inherited;
    end;
    
    procedure TTaskDelay.Execute;
    begin
      inherited;
      while not Terminated do
      begin
        if GetTickCount< FStart then
          Sleep(FOffSet)
        else
        begin
          SendMessage(FHWND, FWM_START, 0, 0);
          Break;
        end;
      end;
    end;
    
    end.
    
    调用方式:
    const
      WM_TASKDELAY = WM_USER + 1003;
      
    type
      TForm1= class(TForm)
      private
        procedure WMTASKDELAY(var msg: TMessage); message WM_TASKDELAY;
      end;
    
    //判断线程是否释放
    //返回值:0-已释放;1-正在运行;2-已终止但未释放;
    //3-未建立或不存在
    function CheckThreadFreed(aThread: TThread): Byte;
    var
      i: DWord;
      IsQuit: Boolean;
    begin
      if Assigned(aThread) then
      begin
        IsQuit := GetExitCodeThread(aThread.Handle, i);
        if IsQuit then           //If the function succeeds, the return value is nonzero.
                                     //If the function fails, the return value is zero.
        begin
          if i = STILL_ACTIVE then    //If the specified thread has not terminated,
                                     //the termination status returned is STILL_ACTIVE.
            Result := 1
          else
            Result := 2;              //aThread未Free,因为Tthread.Destroy中有执行语句
        end
        else
          Result := 0;                //可以用GetLastError取得错误代码
      end
      else
        Result := 3;
    end;
    procedure TForm1.WMTASKDELAY(var msg: TMessage);
    begin
    
    end;
    
    procedure TForm1.edtKHMCChange(Sender: TObject); 
    begin
      case CheckThreadFreed(TaskDelay) of
        0,3:
        begin
          TaskDelay:= TTaskDelay.Create(100, Handle, WM_TASKDELAY);
          TaskDelay.Resume;
        end;
      end;
      TaskDelay.Delay;
    end;

    试试看吧!



    展开全文
  • Delphi线程下的ADO编程 前言:几个月前接到一个任务:将一后台程序访问数据库的方式从BDE改为ADO,原因是由于业务量的增加,通过BDE不论是向数据库写入数据还是从数据库中读出数据的速度都变得无法忍受,大家都...

    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的对象DataModule1,DataModule1是一全局变量,下面是数据库的访问模式的结构模型图。(实际结构要复杂很多)

     

     

    数据库:
     
    ADOConnection1
     
    ADOConnection2
     
    Table1
     
    Table2
     
    ①ADOQuery1
     
    ②ADOQuery3
     
    ①ADOProcedure1
     
    ①ADOProcedure2
     
    ①UpdateQuery
     
    ③ADOQuery2
     
     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    图1

    说明:

    ①UpdateQuery
     
     

     

                       ADOQuery控件用来修改table2记录,①代表为线程1所有,

    白色代表使用频率很低(颜色越深说明使用频率越高)

     

    ③ADOQuery2
     
     

     

                       查询table2,③代表为线程3所有,使用频率较高

     

    ②ADOQuery3
     
     

     

                       查询table2,③代表为线程2所有,使用频率很高

     

    ①ADOProcedure1
     
               

                          ADO存储过程控件向表table2插入数据,属于线程1频繁使用

     

    ①ADOProcedure2
     
     

     

    修改ADOProcedure1插入的记录,属于线程1频繁使用

     

    其中线程3和线程2使用ADO控件时没有加锁,而线程1的所有访问都加锁了(这样做毫无作用)

     

    程序的结构出来了,问题在哪里呢?接下来我写了一个小小的测试程序,该程序的结构与上面相同,它拥有三个线程和一个DataMoule单元,线程一通过ADOQuery1查询数据库DBTest的table1的记录,线程二通过ADOQuery2向table1中插入记录,线程三通过ADOQuery3修改table1中最后一条记录的某个字段。ADOQuery1、ADOQuery2、ADOQuery3都通过ADOConnection1与数据库DBTest1建立连接,一开始,所有的线程都不做同步,运行,OK!错误出来了其中两个错误正是我所想要的,这就是我的程序报的错啊。

     


    图二

     

    接下来我将三个ADOQuery都加上锁,再运行没问题,我又将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+高级程序设计篇》却说,如果你的程序不是连接多个数据库的话,最好同一数据库使用一个连接,不要使用多个连接。怎么办?谁对谁错?为什么要使用一个连接呢?这主要是从服务器来考虑,因为数据库服务器需要为每个连接分配一定的资源并对其进行维护,连接数越多服务器方所耗的资源就越多,服务器的性能也就越差,所以要尽可能的减少客户端的连接数。好在我的程序是作为服务器程序增加一些连接对数据库服务器的影响不会很大,现在我可以重新设置我的数据库访问结构模型了

     

    数据库:
     
    ADOConnection1
     
    ADOConnection2
     
    Table1
     
    Table2
     
    ①ADOQuery1
     
    ②ADOQuery3
     
    ①ADOProcedure1
     
    ①ADOProcedure2
     
    ①UpdateQuery
     
    ③ADOQuery2
     
    ADOConnection2
     
     

     

     

     

     

     

     

                                                                                  

     

     

     

     

     

     

     

     

     

     

     

     

    图三

     

    我增加了一个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。


    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/weekendw/archive/2002/11/02/16491.aspx

    展开全文
  • delphi2010的日志服务器,绿色版 功能介绍 1,syslog server 2, 接收到日志之后编码为utf8 (如果出现乱码,调整编码) 3,可以把日志保存到文本文件。默认在程序目录下, log目录。按照ip,和日期,分文件存档...
  • 如果你使用多种数据库连接,比如三层中经常切换到MSSQL和Oracle,我们只需在判断 TUniConnection 的连接前事件 OnBeforeConnect 下如下代码: procedure TServDBFunc.ServConnBeforeConnect(Sender: TO
    一般解决方法是在线程开始启用 CoInitialize(nil),线程结束调用 CoUninitialize 。如果你使用多种数据库连接,比如三层中经常切换到MSSQL和Oracle,我们只需在判断 TUniConnection 的连接前事件 OnBeforeConnect 写下如下代码: procedure TServDBFunc.ServConnBeforeConnect(Sender: TObject); begin if (ServConn <> nil) and SameText(ServConn.ProviderName,'SQL Server');then CoInitialize(nil); end; 在TUniConnection 的关闭连接后事件 OnAfterDisconnect 写下如下代码: procedure TServDBFunc.ServConnAfterDisconnect(Sender: TObject); begin if (ServConn <> nil) and SameText(ServConn.ProviderName,'SQL Server');then CoUninitialize; end; 需要注意的是,必须先判断连接控件 (ServConn <> nil) 是否为空,否则,你会陷入指针释放的问题。
    展开全文
  • 如果你使用多种数据库连接,比如三层中经常切换到MSSQL和Oracle,我们只需在判断 TUniConnection 的连接前事件 OnBeforeConnect 下如下代码: procedure TServDBFunc.ServConnBeforeConnect(Sender: TObject); ...
  • 概述:实现单线程多帐户的邮件收发及保存。 功能表: 一。邮件操作 1。收邮件 2。发邮件 3。另存邮件 4。另存附件 5。删除邮件 6。回复邮件 二。帐户操作 1。新建帐户 2。删除帐户 3。帐户设置 三。地址簿操作 1。...
  • 假如线程方法效果更好,共享!先导入SQLDMO生成SQLDMO_TLB.pas文档unit Unit3;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs,SQLDMO_TLB, StdCtrls, ...
  • Delphi技术文档

    2013-06-01 19:56:57
    Delphi编程实现图像的局部放大、Delphi编程实现硬盘数据读写、保护与恢复、Delphi编写服务程序实现机房机器自动更新、Delphi编写浏览器URL过滤软件、Delphi的多线程技术在Socket编程中的应用、Delphi线程的安全...
  • 数据库压力测试

    2011-01-05 11:28:00
     本来打算用API,想一想算了,又要同步又要自己控制很多东西,另外的原因是多个线程要调用同一个函数,网上查了一下,说是可能有问题,原因不明,终了还是采用了DELPHI线程类,简单的事情更简单了。...
  • Delphi中的Dispose的问题

    2015-09-30 06:45:45
    了这样的一个Delphi程序: 1号线程数据库中取出信息,然后放到一个队列Q中; 2号线程从Q中取出信息进行处理. 当线程2从队列Q中取出数据进行处理之后就会使用Dispose来释放它,然后再取,再处理,再释放 但是出现...
  • Delphi编程100例

    2009-09-22 08:59:12
    线程数据库 使用远程存储过程 数据模块的同步显示 建立Web服务的数据提供端 建立Web服务的数据访问端 开发WebSnap数据库程序 建立ActiveForm数据浏览 建立数据查询WebServices服务器端 数据查询Web服务客户端...
  • Delphi深度编程技术

    2009-09-09 17:17:31
    9.3.1 发送数据部分设计(向串口数据) 9.3.2 数据部分设计(从串口读数据) 9.3.3 程序的具体设计和实现 9.4 利用SPC0MM组件实现串口通信编程 9.4.1 SPCOMM组件的安装 9.4.2 SPCOMM组件的属性、方法和事件 ...
  • 找工作的时候 面试官给我...比对两个文件夹下的文件 取出不同的文件(非文件名)放于第三个文件夹下 还要求利用线程 于是了一下 只能说基本上符合了要求 用的是md5方法 delphi开发语言 access 数据库 都有打包在里面
  • 编写可移植代码\r\n\r\n4.1 版本兼容的共性\r\n4.1.1 版本判断\r\n4.1.2 单元...的类型常量\r\n4.4.2 Cardinal一元取反操作\r\n4.5 从Delphi 4升级\r\n4.5.1 RTL问题\r\n4.5.2 VCL问题\r\n4.5.3 Internet开发主题\r\n...
  • Delphi7编程100例

    2004-09-02 11:32:44
    线程数据库 使用远程存储过程 数据模块的同步显示 建立Web服务的数据提供端 建立Web服务的数据访问端 开发WebSnap数据库程序 建立ActiveForm数据浏览 建立数据查询WebServices服务器端 数据...
  • 编写可移植代码\r\n\r\n4.1 版本兼容的共性\r\n4.1.1 版本判断\r\n4.1.2 单元...的类型常量\r\n4.4.2 Cardinal一元取反操作\r\n4.5 从Delphi 4升级\r\n4.5.1 RTL问题\r\n4.5.2 VCL问题\r\n4.5.3 Internet开发主题\r\n...
  • Delphi7 编程 100 实例

    2007-09-18 00:34:51
    ToolBar工具栏控件的使用 动态建立主菜单选项 窗口界面的动态分隔条...线程数据库 使用远程存储过程 数据模块的同步显示 建立Web服务的数据提供端 建立Web服务的数据访问端 开发WebSnap数据库...
  • delphi7编程百例

    2007-05-10 16:07:36
    ToolBar工具栏控件的使用 动态建立主菜单选项 窗口界面的动态...线程数据库 使用远程存储过程 数据模块的同步显示 建立Web服务的数据提供端 建立Web服务的数据访问端 开发WebSnap...
  • Delphi案例开发.源代码

    热门讨论 2009-07-22 13:39:26
    16)UnitSearch.pas-----------实现百度、新浪等搜索引擎线程定义的单元文件 以上是code文件夹的主要文件,也是本案例工程的所有代码文件,其中ChannelPlayer.dpr是工程文件,记录本工程的信息;其他的窗体都是...
  • ToolBar工具栏控件的使用动态建立主菜单选项窗口界面的动态分隔条动态设置...线程数据库使用远程存储过程数据模块的同步显示建立Web服务的数据提供端建立Web服务的数据访问端开发WebSnap数据库程序建立ActiveForm数据...
  • Delphi 6集成开发环境

    2010-09-01 19:07:30
    第1 章 Delphi 集成开发环境..........1 1.1 Delphi 6.0 简介............................................ 1 1.2 Delphi 可视化开发环境简介...................... 2 1.2.1 对象编辑器(Object Inspector)....3 ...
  • 第三十一讲 多线程应用 第三十二讲 Hook技术 第三十三讲 自定义控件 第七篇数据库编程 第三十四讲 使用Rave控件 第三十五讲 创建数据库 第三十六讲 图书管理系统 第三十七讲 ADO技术 第三十八讲 捕捉异常 第三十九讲...
  • 基础篇结合示例论述了Delphi的深度编程技术,其中包括9章,分别为:理解Windows消息、进程与线程、自定义组件的编写、文件操作、创建DLL应用程序、两层数据库应用程序、多层数据库应用程序、Socket编程、串口编程;...
  • 开发环境: Delphi7+WinXP说明: 一个用delphi写的安装程序. 经常在网上看到一些网友询问用什么工具来作安装程序,或是某某安装程序的用法.想了一下,其实也很好作. 主要原理是把要安装的文件作成资源文件,安装时再把...
  • delphi.6应用开发参考

    2010-08-11 15:19:42
    第1 章 Delphi 集成开发环境..........1 1.1 Delphi 6.0 简介............................................ 1 1.2 Delphi 可视化开发环境简介...................... 2 1.2.1 对象编辑器(Object Inspector)....3 ...

空空如也

空空如也

1 2 3 4
收藏数 66
精华内容 26
关键字:

delphi线程写数据库