I have recently been developed by the Call Center's agent-end and server software development. The seating end login section is to extract host information, and then submitted to the remote server using the socket, the server is looking for information in the background database, comparing, see if the seat is allowed The host is logged in because SQL Server cannot be installed in my computer, so the background database temporarily uses the Access small database to replace it. It can be changed to the SQLServer database in the later period. I use two tables in the background database. I use the Workmark field to associate it. Less, if you find the information in the first table, you will immediately enter the second table, if the information in the first table is in line, it returns the information in the second table of the client because the seat end host There are more than 200, in order to prevent several hosts from verifying information, causing a conflict, I have established multi-threads in the server side, using threads to check the background in the background, and the results of the results of the results, after writing success, discoven when a host After the connection, you can test success, however, when the second or later thread is generated, the data set can find the correct information in the first table, but when entering the second table, it will be found in the correct lookup condition. When the information is found, the information found is NIL, and after tracking, discovery, actually ADO has found the correct information, but it has been successfully sent, but it can't receive it. At the time, I published a post to seek help. , Original content: http://expert.9cbs.net/expert/topic/1420/1420051.xml? Temp = .3060114
Some friends say that the Access database does not provide multi-threaded access, but I have heard that many forums seem to use Access to look for the background thread. Turning about MSDN's instructions about COM: Discovering the lack of the two two function processes in my thread
Coinitialize (NIL); Any access to the COM object should be used. When the thread is closed; otherwise the ADO is definitely wrong, I believe that there are certain friends who have experienced this problem:
My thread code is as follows:
Unit UNITQuerythread;
Interface
Uses Windows, Sysutils, Classes, Dialogs, ADODB, DB, NMMSG, ActiveX {must have};
type QueryThread = class (TThread) private FComputerInfor, FIPaddressinfo: string; // transmitting information FAdoQuery, FAdoQUserInfor: TadoQuery; // a dynamically generated table, Table 2 Fadoconnection: Tadoconnection; // dynamically generated connection Fnmmsg, FNMretureMSG: TNMMSG ; // Used to send a component fileStream: TFileStream; Procedure ExtractinFor (TRANSINFO: String {Customized Process {Customized Process}); Procedure ShellexeQuery; Destructor Destroy;
protected procedure Execute; override; publicconstructor create (ComputerInfor: string; {the transmission of computer information} IPaddressinfo: string {transmitted IP address information}; nmmsg, NMretureMSG: TNMMSG); end; var ExtractDomainUser: string; // extract Domain User Name ExtractComputerName: String; // Extract Computer Name ExtractDomainName: String; // Extract Domain Strlist: TstringList; iplist: tstringlist; // Save IP Address Information Const Defeat = ' Defeat '; // Verification failure, you must log out of the client, re-write importation in the database
Uses UnitSendthread;
constructor QueryThread.create (ComputerInfor, IPaddressinfo: string; nmmsg, NMretureMSG: TNMMSG); begin CoInitialize (nil); // com object must be initialized using inherited create (false); FreeOnTerminate: = true; FComputerInfor: = ComputerInfor; FIPaddressinfo: = Ipwwdressinfo; iplist: = tstringlist.create; // Create IP list FadoQuery: = tadoquery.create (nil); // Dynamically generate table a fadoquserinfor: = tadoQuery.create (nil); // Dynamically generate table 2 fadoconnection: = Tadoconnection.Create (nil); // dynamically generated connection Fadoconnection.LoginPrompt: = false; Fadoconnection.KeepConnection: = true; Fadoquery.Connection: = Fadoconnection; FAdoQUserInfor.Connection: = Fadoconnection; Fadoconnection.ConnectionString: = 'Provider = Microsoft .Jet.oledb.4.0; data source = personformation.mdb; mode = read; persist security info = false ';
Fnmmsg: = nmmsg; fnmreturemsg: = nmreturemsg; strlist: = tstringlist.create; end;
Destructor Querythread.Destroy; begin fadoquery; fadoquserinfor.free; fadoconnection.free; strlist.free; iplist.free; counitialize; // must use inherited destroy;
Procedure querythread.execute; begin
Try begin extractinfor (FComputerInfor); // perform information extraction synchronize (shellexeQuery); // end; Except
Self.Terminate;
END;
END;
Procedure querythread.extractinfor (transinfo: string); // change the process to extract the various strings of the skewers in the split //; J: Array [1..2] of integer; // Used to save the splitter Position h, l, m, n: integer; // perform cycle parameters at the combined string, first empty extractDomainuser: = '; extractdomainname: ='; extractComputername: = '; h: = 1 ;
/ / ========================================= t begin for i: = 1 to Length (Transinfo) DO
IF Transinfo [I] = '#' TEN / / Found Begin J [H]: = i; Inc (H); Continue; // Jump out of the loop END;
Begin for l: = 1 to j [1] -1 DO ExtractDomainuser: = ExtractDomainuseuser: = ExtractDomainuser Transinfo [L]; // Extract login username: // showMessage (extractDomainuser); for m: = j [1] 1 To J [2] -1 DO ExtractDomainName: = ExtractDomainName Transinfo [M]; // Extract Domain Controller Name // ShowMessage (ExtractDomainName); for N: = J [2] 1 To Length (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRIM (TRENFO) ) Do ExtractComputername: = extractComputername Transinfo [N]; // Extract computer name // showMessage (extractComputerName); end; end; // perform exception handlept // MessageBox (0, 'information extraction error!', ' message ', mb_iconinformation); end; end; procedure QueryThread.ShellexeQuery; var mark: string; // save the job number to find information SkillInfor: string; RetureInformation: string; // returns the client's information 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: / / =========================================================================================================================================================================================== ===================== f (FadoQuery.fieldByname ('Workmark') or (FadoQuery.fieldByname ('privilege'). Asstring = '') THEN // No time to check the work number information beginfnmmsg.disconnect; fnmmsg.host:=FipAddressinfo; fnmmsg.port: = 6711; fnmmsg.fromname: = 'a'; fnmmsg.postiTiT (Defeat); // Nothing to find Permissions and work marks send error messages fadoquery.active: = false; end
else // query to the job number, and permission information, get all the information from the order // @@@@@@@@@@@@@@@@@@@@@@@@@@@@ even table @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ beginstrlist .Clear; strlist.add (FadoQuery.fieldByname ('Workmark'). Asstring); // Write the work from Mark: = fadoQuery.fieldbyName ('Workmark'). Asstring; // Write the work from Mark temporary variable
FadoQuery.close; // Close the first dataset // =========== Enter the second table to find ================== ====================================== with fadoquserinfor do begin if Active = true kilose; // Close the data set SQL.CLEAR;
SQL.Add ('Select * from worker where workmark =' '"' mark '"); // This section may require avatar content prepared: = true; open; // Connect the second thread here problem
IF (FieldByName) or (FieldByname ('Name'). asstring = '') or (FieldByname ('SkillLevel'). Asstring = ') Then Begin ShowMessage (' NIL ') Fnmmsg.disconnect; fnmmsg.host := fipaddressInfo; fnmmsg.port: = 6711; fnmmsg.fromname: = '; fnmmsg.post (defeat); // Send Error message close; endelse // If you find a phone number Begin
strlist.add (fieldbyname ( 'Name') asstring.); // write Name SkillInfor: = fieldbyname ( 'SkillGroup') asstring; strlist.add (fieldbyname ( 'SkillGroup') asstring 'service processing =' fieldbyname.. ('SkillLevel'); // Shanghai Business Processing = 1 strlist.add ('Phone'). Asstring); // Write phone number RetureInformation: = strlist.strings [0] {IN} '#' strlist.strings [1] {Name} '#' strlist.strings [2] '#' {Skill Information} Strlist.Strings [3] {Phone Number}; // Edit; / / Annoy will give the client's information // fieldByname ('islogon'). Asstring: = '1'; // Successfully logged in, write success mark // POST;
Fnmreturemsg.disconnect; fnmreturemsg.host: = fipaddressinfo; fnmreturemsg.port: = 6722; // East port is 6722; fnmretureMsg.Post (RetureInformation); // Return successful information
/ ··························································································· 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 'service processing =' fieldbyname ( 'SkillLevel') asstring); {index3 SkillGroup} IPlist.Add (fieldbyname ( 'IPaddress') asstring);:... // ip address all Keep to memory //showMessage (FieldbyName (').Asstring); iPlist.savetofile (FieldbyName (' skillgroup '). Asstring ' iPlst.i NI '); next; end; WorkGroupUserInfor.SaveToFile (fieldByName (' SkillGroup ') asstring .' Ini ');. Close; end; end; end; end; except // query failed to prevent begin FAdoQuery.close; FAdoQUserInfor.close ;
END;
End. Note: Use these two functions to add ActiveX.PAS units, otherwise, you cannot run.
I personally think that if developing ADO-based multi-threaded operations, it is best to place a connection in each thread, and data sets and data connectors use dynamic generation, of course, you must pay attention to the normal release, Otherwise, your computer will quickly crack down, huh, Of course, there is a second way, you can generate a data module, static place the data set and the Adoconnection component, and then make the data module not generated when the program is started, but can be The generation of the thread is generated, this method can also be, interested friends can try the execution efficiency between the two. For ADO, I think if the start function and the later release function are not reported, it should be a bug.
Thank you for your concern:
QQ: 53997882 Welcome everyone to exchange