使用ADO多线程访问ACCESS数据库的开发

2012世界末日yu

2012世界末日yu

2016-02-19 13:30

下面图老师小编跟大家分享一个简单易学的使用ADO多线程访问ACCESS数据库的开发教程,get新技能是需要行动的,喜欢的朋友赶紧收藏起来学习下吧!

本人最近正在进行呼叫中心的座席端和服务器软件开发,座席端登录部分是进行提取主机信息,然后使用SOCKET提交给远程服务器,服务器再在后台数据库中进行查找信息,进行对比,看是否允许座席端主机登录,因为我的电脑中无法安装SQLSERVER,所以 ,

后台数据库暂时使用access小型数据库进行代替,到后期可以改为SQLSERVER数据库,,我在后台数据库中使用了两个表,使用WORKMARK字段将其相关联,如果在第一个表中查找到信息以后马上会进入第二个表中进行查找,如果第一个表中的信息符合,就返回个客户第二个表中的信息,因为座席端主机有200多台,为了防止几台主机同时进行验证信息,引起冲突,我在服务器端建立多线程,利用线程进行后台的查询,以及查找结果的回传,编写成功后进行测试,发现当一个主机连接后可以测试成功,但是,当第二个或者以后的线程产生时,数据集在第一个表中可以查到正确的信息,但是进入第二个表中时,会发现按照正确的查找条件进行查找时,查到的信息都为NIL,而且经过跟踪,发现,其实ADO已经找到了正确的信息,而且已经发送成功了,但是却无法接收到,当时我在论坛中发表了一个帖子寻求帮助,原贴内容:http://expert.csdn.net/Expert/topic/1420/1420051.xml?temp=.3060114

有些朋友说可能ACCESS数据库不提供多线程访问,但是我听说很多的论坛中好像都使用了ACCESS进行后台线程的查找的。翻看MSDN中关于COM的说明:发现我的线程中竟然缺少最重要的两个函数过程

CoInitialize( nil );凡是访问com对象都应该使用。线程的关闭时应该使用CoUnInitialize;否则ADO肯定出错,我相信肯定有不少的朋友经历过这种问题的:

我的线程代码如下:

unit Unitquerythread;

interface

uses
  windows,SysUtils,Classes, Dialogs,ADODB,db, NMMSG, ActiveX{必须要有};

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)

type
  QueryThread = class(TThread)
  private
   FComputerInfor,FIPaddressinfo: string;  //传递的信息
   FAdoQuery,FAdoQUserInfor:TadoQuery;  //动态生成的表一,表2
  
   Fadoconnection:Tadoconnection;  //动态生成的连接
   Fnmmsg,FNMretureMSG:TNMMSG;//用来发送返回信息的组件
filestream:tfilestream;
    procedure ExtractInfor(TransInfo:string{自定义的从该提交信息中分离信息的过程});
    procedure ShellexeQuery;
  Destructor Destroy;

  protected
    procedure Execute; override;
  public
constructor  create(ComputerInfor:string;{传输来的计算机信息}IPaddressinfo:string{传输来的IP地址信息};nmmsg,NMretureMSG:TNMMSG);
  end;
var
  ExtractDomainUser:string;  //提取出来的域用户名
  ExtractComputername:string;//提取出来的计算机名称
  ExtractDomainname:string;//提取出来的域名
  strlist:Tstringlist;
  IPlist:Tstringlist;//保存查找到的本工作组的ip地址信息
  const defeat='defeat';  //验证失败,必须注销客户机,在数据库中重新进行写入

implementation

  uses Unitsendthread;

constructor QueryThread.create(ComputerInfor, IPaddressinfo: string;nmmsg,NMretureMSG:TNMMSG);
begin
  CoInitialize( nil );//使用com对象必须要初始化
  inherited create(false);
  FreeOnTerminate:=true;
  FComputerInfor:=ComputerInfor;
  FIPaddressinfo:=IPaddressinfo;
  IPlist:=Tstringlist.create;//创造ip列表
  FAdoQuery:=TAdoQuery.Create(nil);     //动态生成表一
  FAdoQUserInfor:=TadoQuery.Create(nil);//动态生成表2
  Fadoconnection:=Tadoconnection.Create(nil);//动态生成的连接
  Fadoconnection.LoginPrompt :=false;
  Fadoconnection.KeepConnection :=true;
  Fadoquery.Connection:=Fadoconnection;
  FAdoQUserInfor.Connection :=Fadoconnection;
  Fadoconnection.ConnectionString :='Provider=Microsoft.Jet.OLEDB.4.0;Data Source=PersonInformation.mdb;Mode=Read;Persist Security Info=False';

  Fnmmsg:=nmmsg;
  FNMretureMSG:=NMretureMSG;
  strlist:=Tstringlist.Create;
 
end;

destructor QueryThread.Destroy;
begin
  FAdoQuery.FREE;
  FAdoQUserInfor.FREE;
  Fadoconnection.Free;
  strlist.Free;
  iplist.free;
  CoUnInitialize;//必须使用
inherited destroy;
end;

procedure QueryThread.Execute;
begin

try
 begin
  extractinfor(FComputerInfor);  //进行信息提取
 Synchronize(ShellexeQuery);//
 end;
except

self.Terminate;

end;

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)

end;

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)

procedure QueryThread.ExtractInfor(TransInfo: string);//改过程进行提取用#进行分割//的串里的各个字符串

integer;
j:array [1..2]of integer;//用来保存分割符的位置
H,L,M,N:integer;//进行组合字符串时的循环参数

begin

全局变量,首先清空
      ExtractDomainUser:='';
      ExtractDomainname:='';
      ExtractComputername:='';
      H:=1;

//=================================
 try
    begin
         for i := 1 to length(TransInfo) do

        if TransInfo[i]='#' then //找到了
           begin
            j[H]:=i;
           
            inc(H);
            continue;  //跳出循环
           end;

    BEGIN
     for L:=1 to j[1]-1 do
          ExtractDomainUser:=ExtractDomainUser+TransInfo[L]; //提取的登陆域用户名
          ://showmessage(extractdomainuser);
     for M:=j[1]+1 to j[2]-1 do
          ExtractDomainname:=ExtractDomainname+TransInfo[M];//提取的域控制器名
        //showmessage(extractdomainname);
     for N:=j[2]+1 to length(trim(TransInfo)) do
          ExtractComputername:=ExtractComputername+Transinfo[N];//提取的计算机名
         //showmessage(extractcomputername);
    END;
   end;//进行异常处理
  Except
   // messagebox(0,'信息提取出现错误!','提示信息',mb_iconinformation);
  end;
end;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure QueryThread.ShellexeQuery;
var
    mark:string;   //保存查找到的工号信息
    SkillInfor:string;
    RetureInformation:string; //返回个客户端的信息
    WorkGroupUserInfor:Tstringlist;
    filename:string;

begin
 try
   begin
      
       FAdoQuery.Close;
       Fadoquery.SQL.Clear;
       FAdoQuery.SQL.Add ('SELECT * From LogoN WHERE DomainUser='+'"'+ExtractDomainUser+'"'+'and DomainName='+'"'+ExtractDomainname+'"'+'and ComputerName='+'"'+ExtractComputername+'"'+'and IPaddress='+'"'+FIPaddressinfo+'"');
       FAdoQuery.Prepared :=true;
       FAdoQuery.active:=true;
file://=====================================================================
   if (FAdoQuery.fieldbyname('WorkMark').asstring ='') or (FAdoQuery.fieldbyname('Privilege').asstring='')  then //没有查到工号信息
         begin

             Fnmmsg.Disconnect;
             Fnmmsg.Host:=FIPaddressinfo;
             Fnmmsg.Port :=6711;
             Fnmmsg.FromName :='a';
             Fnmmsg.PostIt(defeat); //没有找到权限和工号则发送错误消息
             FAdoQuery.active:=false;
         end

  else      //查询到了工号,和权限信息 ,从阶连表中得到所有信息
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     begin

              strlist.Clear;
              strlist.Add(FAdoQuery.fieldbyname('WorkMark').asstring);//把工号写入
              mark:=FAdoQuery.fieldbyname('WorkMark').asstring; //将工号写入mark临时变量

              FAdoQuery.close; //关闭第一个数据集
   //===========进入第二个表进行查找===============================================
    with FAdoQUserInfor do
       begin
            
              if active =true then close;   //关闭数据集
              sql.Clear;

              sql.Add('Select * From WORKER Where WorkMark='+'"'+mark+'"'); //该部分可能要求具体化内容
              Prepared :=true;
              open;
              //连接第二个线程时这里出现问题

            if (fieldbyname('Phone').asstring='')or (fieldbyname('Name').asstring='')or (fieldbyname('SkillLevel').asstring='')then
               begin
             showmessage('nil');
                  Fnmmsg.Disconnect;
                  Fnmmsg.Host:= FIPaddressinfo;
                  Fnmmsg.Port :=6711;
                  Fnmmsg.FromName :='b';
                  Fnmmsg.PostIt(defeat);  //发送错误消息
                  close;
               end

           else    //如果找到了电话号码
               begin

                   strlist.add(fieldbyname('Name').asstring);  //写入姓名
                   SkillInfor:=fieldbyname('SkillGroup').asstring;
                   strlist.add(fieldbyname('SkillGroup').asstring+'业务处理='+fieldbyname('SkillLevel').asstring); //上海市业务处理=1
                   strlist.Add(fieldbyname('Phone').asstring);  //写入电话号码
                 
                   RetureInformation :=strlist.Strings[0]{工号}+'#'+strlist.Strings[1]{姓名}+'#'+strlist.Strings[2]+'#'{技能信息}+strlist.strings[3]{电话号码};
                   //edit;                      //烦会给客户端的信息
                  // fieldbyname('IsLogon').asstring:='1'; //登录成功,写入成功标志
                  // Post;

                   FNMretureMSG.Disconnect;
                   FNMretureMSG.Host :=FIPaddressinfo;
                   FNMretureMSG.Port:=6722; //回传信息远程端口为6722;
                   FNMretureMSG.PostIt(RetureInformation);  //返回成功的信息

/·······························
   {进行查询工作组信息,然后传送信息}
                   if active =true then close;
                   sql.clear;
                   SQL.Add('SELECT * FROM WORKER WHERE SkillGroup='+'"'+SkillInfor+'"');
                   open;
                
                   WorkGroupUserInfor:=Tstringlist.create;

                 while not eof do
                  begin
                   WorkGroupUserInfor.Add(fieldByName('Name').asstring ); {index0 name}
                   WorkGroupUserInfor.Add(fieldByName('WorkMark').asstring ); {index1 workmark}
                   WorkGroupUserInfor.Add(fieldByName('Phone').asstring );    {index2 Phone}
                   WorkGroupUserInfor.Add(fieldByName('SkillGroup').asstring +'业务处理='+fieldbyname('SkillLevel').asstring);{index3 SkillGroup}
                   IPlist.Add(fieldbyname('IPaddress').asstring); ://所有的ip地址保留到内存中
                   //showmessage(fieldbyname('IPaddress').asstring);
                   iplist.SaveToFile (fieldByName('SkillGroup').asstring+'IPlst.INI');
                   next;
                 end;
                 WorkGroupUserInfor.SaveToFile(fieldByName('SkillGroup').asstring+'.ini');
                 close;
             end;
          end;
     end;
   end;
  except      //防止查询失败
    begin
      FAdoQuery.close;
      FAdoQUserInfor.close;
   end;
 end;

 end;

end.
注意:使用这两个函数应该加上activex.pas单元,否则,无法运行。

我个人认为,如果开发基于ADO的多线程操作,最好在每个线程中放置一个连接,而数据集和数据连接都使用动态生成,当然你必须要注意必须要保证线程能过正常的释放,否则你的电脑很快就快死机了,呵呵,当然还有第二种方法,你可以生成一个数据模块,静态放置数据集和ADOCONNECTION组件,然后使该数据模块不在程序开始时生成,而可以在线程中动态的生成,这种方法也可以,有兴趣的朋友可以试一下二者之间的执行效率。

而对于ADO,我认为在开始情况下,如果不初始函数和后来的释放函数,却不能报错,应该是一个BUG吧

展开更多 50%)
分享

猜你喜欢

使用ADO多线程访问ACCESS数据库的开发

编程语言 网络编程
使用ADO多线程访问ACCESS数据库的开发

使用ADO.NET访问数据库

电脑网络
使用ADO.NET访问数据库

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

使用MIDAS访问远程Access数据库

编程语言 网络编程
使用MIDAS访问远程Access数据库

DAO访问ACCESS数据库

编程语言 网络编程
DAO访问ACCESS数据库

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

Access数据库开发技巧

编程语言 网络编程
Access数据库开发技巧

ACCESS数据库访问组件(四)

电脑网络
ACCESS数据库访问组件(四)

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

22寸电脑显示器分辨率最佳是多少?

22寸电脑显示器分辨率最佳是多少?

GE Access将在北美分销McDATA全系列产品

GE Access将在北美分销McDATA全系列产品
下拉加载更多内容 ↓