This article is extended the content of Multithreaded Delphi Database Queries, which is mainly dbGO(ADO) change to Dbexpress(DBX).
The same opinion is as below mentioned:
1. Solve: “Canvas does not allow drawing”.
2. Main TSQLConnection Cannot be used!
And the superiority of DBX is:
1. DBX is read only and unidirectional.
2. Device is very flexible.
Because SQLDataSet’s property always ‘string’ and need add SQLConnection, so we can modify this code:
Multithreading in Dbexpress (DBX)
Let's say you want to display orders for 3 selected customers in a Delphi list box control.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | TCalcThread = class(TThread) private procedure RefreshCount; protected procedure Execute; override; public ConnStr : string; SQLString : string; cnThread: TSQLConnection; ListBox : TListBox; Priority: TThreadPriority; TicksLabel : TLabel; Ticks : Cardinal; end; |
Well, DBX is not support ACCESS in
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | procedure TDbxThreadedForm.ReConnection(); begin // // MSACCESS // dbx_access_connect.AccessConnect(SQLConnection, // mdb_file_name: 'C:\Program Files\Common Files\CodeGear Shared\Data\dbdemos.mdb', // DNS_NAME '', // DirectOdbc True, // LoginPrompt False, // UserName '', // Password '', // AdditionalOptions 'coEnableBCD=0', // bUnicodeOdbcApi True, // bAnsiStringField False, // bUnicodeDriver True ); end; |
When the 3 customers are selected from the drop down box, we create 3 instances of the CalcThread:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | procedure TDbxThreadedForm.Button1Click(Sender: TObject); var s, sg: string; c1, c2, c3 : integer; begin s := ' SELECT O.SaleDate, MAX(I.ItemNo) AS ItemCount ' + ' FROM Customer C, Orders O, Items I ' + ' WHERE C.CustNo = O.CustNo AND I.OrderNo = O.OrderNo ' ; sg := ' GROUP BY O.SaleDate '; c1 := Integer(ComboBox1.Items.Objects[ComboBox1.ItemIndex]); c2 := Integer(ComboBox2.Items.Objects[ComboBox2.ItemIndex]); c3 := Integer(ComboBox3.Items.Objects[ComboBox3.ItemIndex]); Caption := ''; ct1 := RunThread(Format('%s AND C.CustNo = %d %s',[s, c1, sg]), lbCustomer1, tpTimeCritical, lblCustomer1); ct2 := RunThread(Format('%s AND C.CustNo = %d %s',[s, c2, sg]), lbCustomer2, tpNormal,lblCustomer2); ct3 := RunThread(Format('%s AND C.CustNo = %d %s',[s, c3, sg]), lbCustomer3, tpLowest, lblCustomer3); end; |
Traps and Tricks - Multithreaded DBX Queries
The main code goes in the thread's Execute method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | procedure TCalcThread.Execute; var Qry : TSQLDataSet; i : integer; begin inherited; ticks := GetTickCount(); //CoInitialize(nil); //CoInitialize was not called cnThread := DbxThreadedForm.SQLConnection.CloneConnection; Qry := TSQLDataSet.Create(nil); try Qry.SQLConnection := cnThread; Qry.CommandText := SQLString; ListBox.Clear; Qry.Open; for i:= 0 to 100 do begin while NOT Qry.Eof and NOT Terminated do begin ListBox.Items.Insert(0, Format('%s - %d', [Qry.Fields[0].asString,Qry.Fields[1].AsInteger])); //Canvas Does NOT Allow Drawing if not called through Synhronize Synchronize(RefreshCount); Qry.Next; end; //while if Terminated then break; Qry.First; ListBox.Items.Add('*---------*'); end; // for finally Qry.Free; FreeAndNil(cnThread); end; //CoUninitialize(); ticks := GetTickCount - ticks; TicksLabel.Caption := 'Ticks: ' + IntToStr(ticks); end; //TCalcThread.Execute; |
Conclusion
DBX will auto be called CoInitialize and CoUninitialize. So we can to comment it. :P
Attention: Similarly, you cannot use the TSQLConnection object from the main thread (application). (Remember free the TSQLConnection object)
You must use the Synchronize procedure to "talk" to the main thread and access any controls on the main form.
Be sure to download the demo application to explore and learn more about multithreaded queries with DBX and Delphi .
Source:
沒有留言:
張貼留言