Info

Multithreaded Delphi-databasequery's

Multithreaded Delphi-databasequery's

Het ontwerp van een Delphi-toepassing wordt in één thread uitgevoerd. Om sommige delen van de applicatie te versnellen, wilt u misschien besluiten om meerdere gelijktijdige uitvoeringspaden toe te voegen aan uw Delphi-applicatie.

Multithreading in database-applicaties

In de meeste scenario's zijn database-applicaties die u maakt met Delphi single threaded - een query die u uitvoert op de database moet worden voltooid (verwerking van de queryresultaten) voordat u een andere set gegevens kunt ophalen.

Om gegevensverwerking te versnellen, bijvoorbeeld het ophalen van gegevens uit de database om rapporten te maken, kunt u een extra thread toevoegen om het resultaat op te halen en te bewerken (recordset).

Lees verder om meer te weten te komen over de 3 vallen in multithreaded ADO-databasequery's:

  1. Oplossen: "CoInitialize werd niet genoemd".
  2. Oplossen: "Canvas staat tekenen niet toe".
  3. Hoofd TADoConnection kan niet worden gebruikt!

Scenario voor klantorders

In het bekende scenario waarin een klant bestellingen plaatst die artikelen bevatten, moet u mogelijk alle bestellingen voor een bepaalde klant weergeven samen met het totale aantal artikelen per bestelling.

In een "normale" applicatie met één thread, moet u de query uitvoeren om de gegevens op te halen en vervolgens de recordset herhalen om de gegevens weer te geven.

Als u deze bewerking voor meerdere klanten wilt uitvoeren, moet u dat doen voer de procedure opeenvolgend uit voor elk van de geselecteerde klanten.

In een multithreaded scenario kunt u de databasequery voor elke geselecteerde klant uitvoeren in een afzonderlijke thread-en laat de code dus meerdere keren sneller uitvoeren.

Multithreading in dbGO (ADO)

Stel dat u bestellingen voor 3 geselecteerde klanten wilt weergeven in een Delphi-keuzelijstbesturing.

type

TCalcThread = klasse(TThread)
  

privaat

    procedure RefreshCount;
  

beschermde

    procedure voeren; override;
  

openbaar

ConnStr: widestring;

SQLString: widestring;

ListBox: TListBox;

Prioriteit: TThreadPriority;

TicksLabel: TLabel;

Teken: kardinaal;

  einde;

Dit is het interfacedeel van een aangepaste threadklasse die we gaan gebruiken om alle bestellingen voor een geselecteerde klant op te halen en uit te voeren.

Elke bestelling wordt weergegeven als een item in een keuzelijst (Keuzelijst veld). De ConnStr veld bevat de ADO-verbindingsreeks. De TicksLabel bevat een verwijzing naar een TLabel-besturingselement dat wordt gebruikt om uitvoeringstijden van threads weer te geven in een gesynchroniseerde procedure.

De RunThread procedure maakt en start een instantie van de TCalcThread-threadklasse.

functie TADOThreadedForm.RunThread (SQLString: widestring; LB: TListBox; Priority: TThreadPriority; lbl: TLabel): TCalcThread;

var

CalcThread: TCalcThread;

beginnen

CalcThread: = TCalcThread.Create (true);

CalcThread.FreeOnTerminate: = true;

CalcThread.ConnStr: = ADOConnection1.ConnectionString;

CalcThread.SQLString: = SQLString;

CalcThread.ListBox: = LB;

CalcThread.Priority: = Prioriteit;

CalcThread.TicksLabel: = lbl;

CalcThread.OnTerminate: = ThreadTerminated;

CalcThread.Resume;

Resultaat: = CalcThread;

einde;

Wanneer de 3 klanten worden geselecteerd in de vervolgkeuzelijst, maken we 3 instanties van de CalcThread:

var

s, sg: widestring;

c1, c2, c3: geheel getal;

beginnen

s: = 'SELECT O.SaleDate, MAX (I.ItemNo) AS ItemCount' +

'VAN Klant C, Bestellingen O, Items I' +

'WAAR C.CustNo = O.CustNo EN I.OrderNo = O.OrderNo';

sg: = 'GROUP BY O.SaleDate';


c1: = geheel getal (ComboBox1.Items.ObjectsComboBox1.ItemIndex);

c2: = geheel getal (ComboBox2.Items.ObjectsComboBox2.ItemIndex);

c3: = geheel getal (ComboBox3.Items.ObjectsComboBox3.ItemIndex);


Bijschrift: = ";

ct1: = RunThread (Formaat ('% s EN C.CustNo =% d% s', s, c1, sg), lbCustomer1, tpTimeCritical, lblCustomer1);

ct2: = RunThread (Formaat ('% s EN C.CustNo =% d% s', s, c2, sg), lbCustomer2, tpNormal, lblCustomer2);

ct3: = RunThread (Formaat ('% s EN C.CustNo =% d% s', s, c3, sg), lbCustomer3, tpLowest, lblCustomer3);

einde;

Vallen en trucs met multithreaded ADO-zoekopdrachten

De hoofdcode staat in de thread uitvoeren methode:

procedure TCalcThread.Execute;

var

Qry: TADOQuery;

k: geheel getal;

wordengin
  

geërfd;
CoInitialize (nul);

// CoInitialize werd niet genoemd

Qry: = TADOQuery.Create (nul) ;
  

proberen// MOET EIGEN VERBINDING GEBRUIKEN // Qry.Connection: = Form1.ADOConnection1;

Qry.ConnectionString: = ConnStr;

Qry.CursorLocation: = clUseServer;

Qry.LockType: = ltReadOnly;

Qry.CursorType: = ctOpenForwardOnly;

Qry.SQL.Text: = SQLString;

Qry.Open;

    terwijl NIET Qry.Eof en NIET beëindigd do

beginnen

ListBox.Items.Insert (0, Format ('% s -% d', Qry.Fields0.asString, Qry.Fields1.AsInteger));

      // Canvas staat tekening niet toe als dit niet wordt aangeroepen via Synchroniseren

Synchroniseren (RefreshCount);

Qry.Next;

    einde;
  

Tenslotte

Qry.Free;

einde;

CoUninitialize ();

einde;

Er zijn 3 valkuilen die u moet weten bij het maken van multithreaded Delphi ADO-database-applicaties:

  1. CoInitialize en CoUninitialize moet handmatig worden aangeroepen voordat u een van de dbGo-objecten gebruikt. Als u CoInitialize niet belt, wordt de 'CoInitialize werd niet genoemd"uitzondering. De CoInitialize-methode initialiseert de COM-bibliotheek op de huidige thread. ADO is COM.
  2. U *kan niet* gebruik het TADOConnection-object uit de hoofdthread (applicatie). Elke thread moet zijn eigen database-verbinding maken.
  3. U moet de Synchroniseren procedure om met de hoofdthread te "praten" en toegang te krijgen tot alle bedieningselementen op het hoofdformulier.