18.4.2 應(yīng)用程序分析
18.4.2.1 TDatabase部件的使用
CSDEMO程序中定義了一個數(shù)據(jù)庫模塊部件——TDmEmployee,它是繼承于TDataModule。TDataModule是在Delphi2.0中才出現(xiàn)的專門放置數(shù)據(jù)訪問部件(如TDatabase、TTable和TQuery等)的框架。其它涉及數(shù)據(jù)庫訪問的窗體,只要在uses語句中插入數(shù)據(jù)庫模塊所在的庫單元,該窗體上的數(shù)據(jù)庫部件就可引用相應(yīng)的數(shù)據(jù)庫訪問部件。
在TDmEmployee中定義了一個TDatabase類型的部件──EmployeeDatabase。EmployeeDatagase的主要屬性及屬性值如下:
表18.15 EmployeeDatabase部件主要屬性的取值
━━━━━━━━━━━━━━━━━━━━━━━
屬性 屬性值
───────────────────────
AliasName IBLOCAL
DatabaseName EmployeeDemoDB
KeepConnection True
LoginPrompt False
TransIsolation tiReadCommitted
Params USERNAME = SYSDBA
PASSWORD = masterkey
Connected True
━━━━━━━━━━━━━━━━━━━━━━━
AliasName屬性所指定的IBLOCAL,必須已經(jīng)在BDE中配置好,DatabaseName屬性指定要使用的數(shù)據(jù)庫名,該數(shù)據(jù)庫名是由應(yīng)用程序自己定義的,因此不反應(yīng)到BDE中,該屬性值被TTable、TQuery等DataSet部件引用,并且出現(xiàn)在DataSet部件的DatabaseName 下拉式列表框中。本例中的“EmployeeDemoDB”,被EmployeeTable,SalesTable等所有DataSet部件引用。
Connected為True表明,應(yīng)用程序與數(shù)據(jù)庫將保持聯(lián)接。
KeepConnection屬性為True,表明多次打開和關(guān)閉EmployeeDemoDB數(shù)據(jù)庫中的任意表,應(yīng)用程序?qū)⑹冀K與數(shù)據(jù)庫保持聯(lián)接,這省卻了重復(fù)注冊的開銷。
LoginPrompt 屬性為False,表明應(yīng)用程序自動處理與數(shù)據(jù)庫的聯(lián)接注冊,因此,Params屬性中定義了注冊的用戶名和口令:
USERNAME = SYSDBA
PASSWORD = masterkey
TransIsolation屬性為tiReadCommitted表明,如果存在多個同時事務(wù),則某一事務(wù)只允許讀由其它事務(wù)提交了的數(shù)據(jù)。
程序中EmployeeDatabase的應(yīng)用還與事務(wù)控制等有關(guān)。下文中會介紹這方面的內(nèi)容。
18.4.2.2 不同數(shù)據(jù)庫表的切換
在許多數(shù)據(jù)庫應(yīng)用中都要在不同數(shù)據(jù)庫表之間相互切換,以響應(yīng)用戶輸入條件或系統(tǒng)狀態(tài)的變化。這時,往往需要特別的處理,例如改變光標(biāo)形狀或隱藏數(shù)據(jù)改變等,尤其是在客戶/服務(wù)器應(yīng)用程序中。因為是用SQL語句訪問遠(yuǎn)程數(shù)據(jù)庫,有時還要在服務(wù)器端執(zhí)行計算任務(wù),所以客戶端的數(shù)據(jù)變化會有一定的間隔,因此應(yīng)該讓用戶明白發(fā)生了什么。下面是CSDEMO在數(shù)據(jù)庫表切換時的處理辦法:
procedure TFrmViewDemo.ShowTable( ATable: string );
begin
Screen.Cursor := crHourglass; { 向用戶提示當(dāng)前操作狀態(tài) }
VaryingTable.DisableControls; { 隱藏數(shù)據(jù)變化 }
VaryingTable.Active := FALSE; { 關(guān)閉原來的數(shù)據(jù)庫表 }
VaryingTable.TableName := ATable; { 更新數(shù)據(jù)庫表名 }
VaryingTable.Open; { 打開數(shù)據(jù)庫表 }
VaryingTable.EnableControls; { 顯示所作的修改 }
Screen.Cursor := crDefault; { 重新設(shè)置光標(biāo)形狀 }
end;
crHourglass型光標(biāo)表明正在執(zhí)行SQL查詢。DisableControls和EnableControls的作用是隱藏和顯示數(shù)據(jù)變化。
18.4.2.3 InterBase觸發(fā)器(Trigger)的應(yīng)用
在CSDEMO應(yīng)用程序中,演示觸發(fā)器應(yīng)用的窗體是TFromTriggerDemo;
在該窗體中包含兩個TDBGrid對象。DBGrid1顯示EmployeeTable中的數(shù)據(jù),DBGrid2顯示SalaryHistoryTable中的數(shù)據(jù)。它們的主要屬性及屬性值如下:
表18.16 EmlpoyeeTable部件主要屬性的取值
━━━━━━━━━━━━━━━━━━━━━
屬 性 屬 性 值
─────────────────────
DatabaseName EmployeeDemoDB
IndexFieldName Emp_No
TableName EMPLOYEE
━━━━━━━━━━━━━━━━━━━━━
表18.17 SalaryHistoryTable部件主要屬性的取值
━━━━━━━━━━━━━━━━━━━━━
屬 性 屬 性 表
─────────────────────
DatabaseName EmployeeDemoDB
IndexFieldName Emp_No
MasterFields Emp_No
MasterSource EmployeeSource
TableName SALARY_HISTORY
━━━━━━━━━━━━━━━━━━━━━
這兩個表之間存在兩種關(guān)系:
● 連接關(guān)系
EmployeeTable的記錄變化時,SalaryHistoryTable的數(shù)據(jù)要作相應(yīng)的變化。這種連接關(guān)系是通過索引來實現(xiàn)的。
● 數(shù)據(jù)一致性
對EmployeeTable中的Salary字段的值作修改必須反映到SalaryHistoryTable中,SalaryHistoryTable維護(hù)的是Salary變化的歷史信息。這種數(shù)據(jù)一致性要求在本程序中是通過觸發(fā)器實現(xiàn)的。
觸發(fā)器是在SQL服務(wù)器端執(zhí)行的一段程序,它在服務(wù)器端被觸發(fā)執(zhí)行完成一定的數(shù)據(jù)計算任務(wù)。
下面是InterBase服務(wù)器上與Employee表相關(guān)的觸發(fā)器程序:
Triggers on Table EMPLOYEE:
SAVE_SALARY_CHANGE, Sequence: 0, Type: AFTER UPDATE, Active AS
BEGIN
IF (old.salary <> new.salary) THEN
INSERT INTO salary_history
(emp_no, change_date, updater_id, old_salary, percent_change)
VALUES (
old.emp_no,
'now',
user,
old.salary,
(new.salary - old.salary) * 100 / old.salary);
END
因為觸發(fā)器是相應(yīng)于EMPLOYEE表上的數(shù)據(jù)修改由服務(wù)器自動觸發(fā)執(zhí)行的,所以在客戶應(yīng)用程序上沒有顯式的調(diào)用。在客戶端有打開并顯示數(shù)據(jù)庫表內(nèi)容的程序和當(dāng)SALARY_HISTORY表中數(shù)據(jù)變化時的更新顯示的操作。
procedure TFrmTriggerDemo.FormShow(Sender: TObject);
begin
DmEmployee.EmployeeTable.Open;
DmEmployee.SalaryHistoryTable.Open;
end;
procedure TDmEmployee.EmployeeTableAfterPost(DataSet: TDataSet);
begin
{ 一個雇員的薪水變化將觸發(fā)薪水調(diào)整歷史記錄的變化,
因此,如果SalaryHistory打開的話,就需要更新顯示 }
with SalaryHistoryTable do if Active then Refresh;
end;
18.4.2.4 存儲過程編程
存儲過程也是SQL服務(wù)器上的一段程序,它接收輸入?yún)?shù),在服務(wù)器端執(zhí)行,并將結(jié)果返回客戶端,存儲過程是必須在客戶應(yīng)用程序中顯式調(diào)用的。
對于數(shù)據(jù)庫表中大量記錄的統(tǒng)計和函數(shù)計算,存儲過程是很有用,這樣可以將重復(fù)性計算任務(wù)轉(zhuǎn)換到服務(wù)器,提高數(shù)據(jù)庫應(yīng)用的性能。
Delphi中有兩個部件能操作遠(yuǎn)程數(shù)據(jù)庫服務(wù)器上的存儲過程:TQuery和TStoredProc。
1. TQuery的存儲過程編程
CSDEMO中演示用TQuery調(diào)用存儲過程的窗體是TFrmQueryProc。
TFrmQueryProc中有兩個TDBGrid 部件。DBGrid1顯示EmployeeTable中的數(shù)據(jù)。DBGrid2顯示Project表中的數(shù)據(jù)。使用存儲過程的TQuery部件名為EmployeeProjectsQuery,它的作用是建立Employee 表和Project 表的連接,以實現(xiàn)當(dāng)DBGrid1中記錄改變時,DBGrid2中的數(shù)據(jù)作相應(yīng)的改變。具體的連接任務(wù)是由服務(wù)器上的存儲過程Get_Emp_Proj完成。下面是Get_Emp_Proj的程序:
PROCEDURE Get_Emp_Proj
BEGIN
FOR SELECT proj_id
FROM employee_project
WHERE emp_no = :emp_no
INTO :proj_id
DO
SUSPEND;
END
EMP_NO INPUT SMALLINT
PROJ_ID OUTPUT CHAR(5)
該過程帶兩個參數(shù):
EMP_NO是輸入?yún)?shù),類型是SMALLINT.
PROJ_ID是輸出參數(shù),類型是CHAR(5)
相應(yīng)地,EmployeeProjectsQuery的主要屬性如下:
表18. 18 EmployeeProjectsQuery部件主要屬性的取值
━━━━━━━━━━━━━━━━━━━━━━━━━━
屬 性 屬 性 值
──────────────────────────
DatabaseName EmployeeDemoDB
Params EMP_No(輸入?yún)?shù),Smallint類型)
SQL Select * from
Get_Emp_Proj(:EMP_NO)
━━━━━━━━━━━━━━━━━━━━━━━━━━
TQuery部件是在SQL語句中直接調(diào)用存儲過程。
下面是客戶端的程序:
procedure TFrmQueryProc.FormShow(Sender: TObject);
begin
DmEmployee.EmployeeTable.Open;
EmployeeSource.Enabled := True;
with EmployeeProjectsQuery do if not Active then Prepare;
end;
用Prepare顯式地準(zhǔn)備SQL語句,雖非必須,但可以優(yōu)化SQL的執(zhí)行。
procedure TFrmQueryProc.EmployeeDataChange(Sender: TObject; Field: TField);
begin
EmployeeProjectsQuery.Close;
EmployeeProjectsQuery.Params[0].AsInteger :=
DmEmployee.EmployeeTableEmp_No.Value;
EmployeeProjectsQuery.Open;
WriteMsg('Employee ' + DmEmployee.EmployeeTableEmp_No.AsString +
' is assigned to ' + IntToStr(EmployeeProjectsQuery.RecordCount) +
' project(s).');
end;
該事件處理過程與EmployeeSource的OnDataChange屬性相聯(lián)。用于當(dāng)EmployeeTable數(shù)據(jù)記錄變化時,修正存儲過程的輸入?yún)?shù),并執(zhí)行SQL語句。
相關(guān)推薦:2010年9月計算機(jī)等級考試試題及答案解析專題北京 | 天津 | 上海 | 江蘇 | 山東 |
安徽 | 浙江 | 江西 | 福建 | 深圳 |
廣東 | 河北 | 湖南 | 廣西 | 河南 |
海南 | 湖北 | 四川 | 重慶 | 云南 |
貴州 | 西藏 | 新疆 | 陜西 | 山西 |
寧夏 | 甘肅 | 青海 | 遼寧 | 吉林 |
黑龍江 | 內(nèi)蒙古 |