Delphi数据库编程一日通
Delphi數據庫編程一日通。
通常情況下,利用 Delphi 開發數據庫應用程序,可以使用TTable、TDataSource、TDBEdit、TDBNavigator等構件。只要正確設置了構件的某些屬性,再編寫必要的程序代碼對一些特定事件進行處理,就能夠完成對多種數據庫進行的數據處理,例如:記錄的輸入、修改、刪除和查詢等。這樣做雖然只需要編寫極少量的程序代碼就能達到很好的效果,但如果在程序設計過程中,某些數據表的結構發生了改變,則必須修改與此數據表有關的所有構件的屬性,這將使程序員陷入繁瑣的重復勞動中。
首先來介紹一些查詢技巧
Delphi中實現多線程同步查詢
---- 為避免上述的麻煩,我們可以在編寫網絡數據庫應用程序時采用結構化查詢語言 SQL(Structured Query Language),這樣不僅可以更方便地與諸如 SQL Server、Oracle 等各種后臺數據庫進行動態的數據交換,而且可以使程序的修改和移植更加靈活。我們以數據輸入模塊為例,說明開發客戶服務器應用程序時如何采用 SQL 語句實現數據處理功能。首先,判斷是否已經有事務處理程序在運行,如果有,將其回卷(rollback);如果沒有,則啟動一個新的事務,為數據的最終處理做準備。其次,是設置 SQL 語句,并將其寫入 TQuery 構件中。最后,將事務提交或回卷,至此完成一條記錄的數據輸入。
---- 下面是以頁面中的 TEdit 類型編輯框內容作為數據源,向數據庫輸入記錄的過程代碼:
procedure DataInsert(const qName:TQuery;
szDBName:string;iNum:Integer;
iMark:array of Integer;eName:array of TEdit);
var
i : Integer;
szSQL : string;
begin
if DataModule1.DataBase1.InTransaction=true then
DataModule1.DataBase1.RollBack;
DataModule1.DataBase1.StartTransaction;
szSQL := 'INSERT INTO '+szDBName+' VALUES('
for i:=0 to iNum-1 do
begin
if iMark[i]=0 then
szSQL := szSQL+eName[i].Text {非字符方式}
else
szSQL := szSQL+'"'+eName[i].Text+'"'; {字符方式}
if i=iNum-1 then
szSQL := szSQL+')'
else
szSQL := szSQL+',';
end;
qName.Close; {關閉查詢}
qName.SQL.Clear; {清SQL特性內容}
qName.SQL.ADD(szSQL); {添加SQL內容}
szSQL := 'SELECT * FROM '+szDBName;
qName.SQL.ADD(szSQL);
qName.Open; {返回結果集}
DataModule1.DataBase1.Commit;
end;
---- 以上過程包含五個參數,實現從頁面中的一系列編輯框中讀取數據,并向指定數據表輸入的功能。其中,參數 qName 為頁面中所使用的 TQuery 類構件的名稱;參數 szDBName 是數據表的名稱;參數eName 是 TEdit 類型的數組,列出了頁面中包含數據的各編輯框名稱;參數 iNum 是數據表中的字段個數,也即編輯框的個數;參數 iMark 是一個整數類型的數組,該參數表明相應字段是以何種方式輸入的,如果是字符方式,需要在數據前后兩端加上引號。需要注意的是:在調用本過程之前,應將數據庫連接打開:
DataModule1.DataBase1.Connected := true;
過程調用完成后,將數據庫連接斷開:
DataModule1.DataBase1.Connected := false;
---- 另外,開發網絡數據庫應用程序時,還可以使用存儲過程,即:將預先編譯過的 SQL 語句存儲在服務器上。存儲過程提前運行,且不與程序代碼一同存儲和編譯,因此其對應主程序中的代碼相對簡潔,運行速度也較快。SQL 語句的集中存放,使其修改更容易。
---- 要創建向數據表中輸入數據的存儲過程,代碼編寫舉例如下:
CREATE PROC ProcTest1
@inttest smallint
,@strtest char(4) output
AS
INSERT INTO TEST_User.TRANS_TEST
VALUES(@inttest,@strtest)
SELECT @strtest,* FROM TEST_User.TRANS_TEST
---- 以上代碼向數據表 TEST_User.TRANS_TEST 添加數據,該數據表包括兩個字段:第一個字段為 smallint 類型的數據,參數類型定為 Input(在存儲過程中可缺省);第二個字段數據為長度為4 的字符類型,參數類型為 Output。
---- 其模塊程序的編寫與 DataInsert 過程相似,區別主要在于模塊的中間部分,對應的主要代碼如下:
StoredProc1.Close;
{關閉存儲過程}
StoredProc1.Params[1].ParamType := ptInput;
{設置存儲過程的參數類型}
StoredProc1.Params[1].AsInteger := 1;
{設置存儲過程中參數的數據}
StoredProc1.Params[2].ParamType := ptOutput;
StoredProc1.Params[2].AsString := 'abcd';
StoredProc1.Open; {打開存儲過程}
---- 其中,StoredProc1 是 TStoredProc 類型的構件名稱;Params[1] 是存儲過程中的第一個參數,對應存儲過程 ProcTest1 可以用ParamByName('@inttest')代替;存儲過程的第二個參數與其類似。
---- 實際上,編寫對網絡數據庫進行其他數據處理(如:修改、刪除和查詢等)的模塊,與數據的輸入模塊大體相似,這里就不再贅述了。
優秀的數據庫應用應當充分考慮數據庫訪問的速度問題。通常可以通過優化數據庫、優化 查詢語句、分頁查詢等途徑收到明顯的效果。即使是這樣,也不可避免地會在查詢時閃現一個帶有 SQL符號的沙漏,即鼠標變成了查詢等待。最可憐的是用戶,他(她)在此時只能無奈地等待。遇到急性子的,干脆在此時嘗試 Windows中的其它應用程序,結果致使你的數據庫應用顯示一大片白色的窗口。真是無奈!
本文將以簡單的例子告訴你如何實現線程查詢。還等什么,趕快打開Delphi對照著下面的完整源代碼試試吧。
在查詢時能夠做別的事情或者取消查詢,這只是基本的線程查詢,在你閱讀了Delphi有關線程幫助之后能立刻實現。這里介紹的是多個線程查詢的同步進行。
在Delphi數據庫應用中,都有一個缺省的數據庫會話 Session。通常情況下,每個數據庫應用中只有這一個會話。無論是查詢函數修改數據,在同一時間內只能進行其中的一件事情, 而且進行這一件事情的時候應用程序不能響應鍵盤、鼠標以及其它的 Windows消息。這就是在 窗口區域會顯示一片空白的原因所在。當然,只要將查詢或數據操縱構造成線程對象,情況會好一些,至少可以接受窗口消息,也可以隨時終止查詢或數據操縱,而不會在屏幕上顯示出太難看的白色。不過,這只是解決了問題的一部分。假如在進行一個線程查詢的時候,用戶通過 按鈕或菜單又發出了另一個查詢的命令,這可如何是好,難道終止正在執行的數據庫訪問嗎? 解決之道就是:多線程同步查詢。
實現多線程同步查詢的基本思想是,為每一個查詢組件(如TQuer 組件)創建一個獨占的 數據庫會話,然后各自進行數據庫訪問。需要特別注意的是,因為Delphi中的 VCL組件大多都 不是線程安全的,所以應當在線程查詢結束后再將DataSource組件與查詢組件關聯,從而顯示 在DBGrid組件中。
下面的例子只實現了靜態的線程同步查詢,即線程對象是固定的,并隨窗體的創建和銷毀 而創建和銷毀。你可以就此進行改進,為每一個數據查詢或數據操縱命令創建一個單獨的線程對象,從而達到多線程同步查詢的目的。
注意:應用程序中的線程不是越多越好,因為線程將嚴重吞噬CPU資源,盡管看上去并不明顯。謹慎創建和銷毀線程將避免你的應用程序導致系統資源崩潰。
下面的例子給出了同時進行的兩個線程查詢。第一次按下按鈕時,線程開始執行;以后每次按下按鈕時,如果線程處于掛起狀態則繼續執行,否則掛起線程;線程執行完畢之后將連接 DataSource,查詢結果將顯示在相應的DBGrid中。
{ 這里的多線程同步查詢演示程序僅包括一個工程文件和一個單元文件 }
{ 窗體中放置的組件有: }
{ 兩個Session組件 }
{ 兩個Database組件 }
{ 兩個Query組件 }
{ 兩個DataSource組件 }
{ 兩個DBGrid組件 }
{ 一個Button組件 }
{ 除非特別說明,否則上述各組件的屬性都取默認值(見各組件注釋) }
{ 對于Database組件,就和一般設置一樣,有一個正確的連接即可 }
{ 對于Query 組件,需要在各自的屬性 SQL中添加一些查詢語句,為了 }
{ 看得更清除,建議不要在兩個Query 組件中填寫相同的查詢語句。 }
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Db, DBTables, Grids, DBGrids, StdCtrls;
type
TForm1 = class(TForm)
Session1: TSession; { 屬性SessionName填寫為S1 }
Database1: TDatabase; { 屬性SessionName選擇為S1 }
Query1: TQuery;{ 屬性Database選擇為Database1;屬性SessionName選擇為S1 }
DataSource1: TDataSource; { 屬性DataSet設置為空 }
DBGrid1: TDBGrid; { 屬性DataSource選擇為DataSource1 }
Session2: TSession; { 屬性SessionName填寫為S2 }
Database2: TDatabase; { 屬性SessionName選擇為S2 }
Query2: TQuery;{ 屬性Database選擇為Database2;屬性SessionName選擇為S2 }
DataSource2: TDataSource; { 屬性DataSet設置為空 }
DBGrid2: TDBGrid; { 屬性DataSource選擇為DataSource2 }
BtnGoPause: TButton; { 用于執行和掛起線程 }
procedure FormCreate(Sender: TObject); { 創建窗體時創建線程對象 }
procedure FormDestroy(Sender: TObject); { 銷毀窗體時銷毀線程對象 }
procedure BtnGoPauseClick(Sender: TObject); { 執行線程和掛起線程 }
private
public
end;
TThreadQuery = class(TThread) { 聲明線程類 }
private
FQuery: TQuery; { 線程中的查詢組件 }
FDataSource: TDataSource; { 與查詢組件相關的數據感知組件 }
procedure ConnectDataSource;{ 連接數據查詢組件和數據感知組件的方法 }
protected
procedure Execute; override;{ 執行線程的方法 }
public
constructor Create(Query: TQuery;
DataSource: TDataSource); virtual; { 線程構造器 }
end;
var
Form1: TForm1;
Q1, { 線程查詢對象1 }
Q2: TThreadQuery; { 線程查詢對象2 }
implementation
{$R *.DFM}
{ TThreadQuery類的實現 }
{ 連接數據查詢組件和數據感知組件}
procedure TThreadQuery.ConnectDataSource;
begin
FDataSource.DataSet := FQuery;{ 該方法在查詢結束后才調用 }
end;
procedure TThreadQuery.Execute;{ 執行線程的方法 }
begin
try
FQuery.Open; { 打開查詢 }
Synchronize(ConnectDataSource);{ 線程同步 }
except
ShowMessage('Query Error'); { 線程異常 }
end;
end;
{ 線程查詢類的構造器 }
constructor TThreadQuery.Create(Query: TQuery; DataSource: TDataSource);
begin
FQuery := Query;
FDataSource := DataSource;
inherited Create(True);
FreeOnTerminate := False;
end;
{ 創建窗體時創建線程查詢對象 }
procedure TForm1.FormCreate(Sender: TObject);
begin
Q1 := TThreadQuery.Create(Query1, DataSource1);
Q2 := TThreadQuery.Create(Query2, DataSource2);
end;
{ 銷毀窗體時銷毀線程查詢對象 }
總結
以上是生活随笔為你收集整理的Delphi数据库编程一日通的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Javascript之浏览器对象
- 下一篇: 作者:姚阳(1979-),女,广州市社会