18.4.2 應(yīng)用程序分析
18.4.2.1 TDatabase部件的使用
CSDEMO程序中定義了一個(gè)數(shù)據(jù)庫(kù)模塊部件——TDmEmployee,它是繼承于TDataModule。TDataModule是在Delphi2.0中才出現(xiàn)的專門(mén)放置數(shù)據(jù)訪問(wèn)部件(如TDatabase、TTable和TQuery等)的框架。其它涉及數(shù)據(jù)庫(kù)訪問(wèn)的窗體,只要在uses語(yǔ)句中插入數(shù)據(jù)庫(kù)模塊所在的庫(kù)單元,該窗體上的數(shù)據(jù)庫(kù)部件就可引用相應(yīng)的數(shù)據(jù)庫(kù)訪問(wèn)部件。
在TDmEmployee中定義了一個(gè)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ù)庫(kù)名,該數(shù)據(jù)庫(kù)名是由應(yīng)用程序自己定義的,因此不反應(yīng)到BDE中,該屬性值被TTable、TQuery等DataSet部件引用,并且出現(xiàn)在DataSet部件的DatabaseName 下拉式列表框中。本例中的“EmployeeDemoDB”,被EmployeeTable,SalesTable等所有DataSet部件引用。
Connected為T(mén)rue表明,應(yīng)用程序與數(shù)據(jù)庫(kù)將保持聯(lián)接。
KeepConnection屬性為T(mén)rue,表明多次打開(kāi)和關(guān)閉EmployeeDemoDB數(shù)據(jù)庫(kù)中的任意表,應(yīng)用程序?qū)⑹冀K與數(shù)據(jù)庫(kù)保持聯(lián)接,這省卻了重復(fù)注冊(cè)的開(kāi)銷。
LoginPrompt 屬性為False,表明應(yīng)用程序自動(dòng)處理與數(shù)據(jù)庫(kù)的聯(lián)接注冊(cè),因此,Params屬性中定義了注冊(cè)的用戶名和口令:
USERNAME = SYSDBA
PASSWORD = masterkey
TransIsolation屬性為tiReadCommitted表明,如果存在多個(gè)同時(shí)事務(wù),則某一事務(wù)只允許讀由其它事務(wù)提交了的數(shù)據(jù)。
程序中EmployeeDatabase的應(yīng)用還與事務(wù)控制等有關(guān)。下文中會(huì)介紹這方面的內(nèi)容。
18.4.2.2 不同數(shù)據(jù)庫(kù)表的切換
在許多數(shù)據(jù)庫(kù)應(yīng)用中都要在不同數(shù)據(jù)庫(kù)表之間相互切換,以響應(yīng)用戶輸入條件或系統(tǒng)狀態(tài)的變化。這時(shí),往往需要特別的處理,例如改變光標(biāo)形狀或隱藏?cái)?shù)據(jù)改變等,尤其是在客戶/服務(wù)器應(yīng)用程序中。因?yàn)槭怯肧QL語(yǔ)句訪問(wèn)遠(yuǎn)程數(shù)據(jù)庫(kù),有時(shí)還要在服務(wù)器端執(zhí)行計(jì)算任務(wù),所以客戶端的數(shù)據(jù)變化會(huì)有一定的間隔,因此應(yīng)該讓用戶明白發(fā)生了什么。下面是CSDEMO在數(shù)據(jù)庫(kù)表切換時(shí)的處理辦法:
procedure TFrmViewDemo.ShowTable( ATable: string );
begin
Screen.Cursor := crHourglass; { 向用戶提示當(dāng)前操作狀態(tài) }
VaryingTable.DisableControls; { 隱藏?cái)?shù)據(jù)變化 }
VaryingTable.Active := FALSE; { 關(guān)閉原來(lái)的數(shù)據(jù)庫(kù)表 }
VaryingTable.TableName := ATable; { 更新數(shù)據(jù)庫(kù)表名 }
VaryingTable.Open; { 打開(kāi)數(shù)據(jù)庫(kù)表 }
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;
在該窗體中包含兩個(gè)TDBGrid對(duì)象。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
━━━━━━━━━━━━━━━━━━━━━
這兩個(gè)表之間存在兩種關(guān)系:
● 連接關(guān)系
EmployeeTable的記錄變化時(shí),SalaryHistoryTable的數(shù)據(jù)要作相應(yīng)的變化。這種連接關(guān)系是通過(guò)索引來(lái)實(shí)現(xiàn)的。
● 數(shù)據(jù)一致性
對(duì)EmployeeTable中的Salary字段的值作修改必須反映到SalaryHistoryTable中,SalaryHistoryTable維護(hù)的是Salary變化的歷史信息。這種數(shù)據(jù)一致性要求在本程序中是通過(guò)觸發(fā)器實(shí)現(xiàn)的。
觸發(fā)器是在SQL服務(wù)器端執(zhí)行的一段程序,它在服務(wù)器端被觸發(fā)執(zhí)行完成一定的數(shù)據(jù)計(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
因?yàn)橛|發(fā)器是相應(yīng)于EMPLOYEE表上的數(shù)據(jù)修改由服務(wù)器自動(dòng)觸發(fā)執(zhí)行的,所以在客戶應(yīng)用程序上沒(méi)有顯式的調(diào)用。在客戶端有打開(kāi)并顯示數(shù)據(jù)庫(kù)表內(nèi)容的程序和當(dāng)SALARY_HISTORY表中數(shù)據(jù)變化時(shí)的更新顯示的操作。
procedure TFrmTriggerDemo.FormShow(Sender: TObject);
begin
DmEmployee.EmployeeTable.Open;
DmEmployee.SalaryHistoryTable.Open;
end;
procedure TDmEmployee.EmployeeTableAfterPost(DataSet: TDataSet);
begin
{ 一個(gè)雇員的薪水變化將觸發(fā)薪水調(diào)整歷史記錄的變化,
因此,如果SalaryHistory打開(kāi)的話,就需要更新顯示 }
with SalaryHistoryTable do if Active then Refresh;
end;
18.4.2.4 存儲(chǔ)過(guò)程編程
存儲(chǔ)過(guò)程也是SQL服務(wù)器上的一段程序,它接收輸入?yún)?shù),在服務(wù)器端執(zhí)行,并將結(jié)果返回客戶端,存儲(chǔ)過(guò)程是必須在客戶應(yīng)用程序中顯式調(diào)用的。
對(duì)于數(shù)據(jù)庫(kù)表中大量記錄的統(tǒng)計(jì)和函數(shù)計(jì)算,存儲(chǔ)過(guò)程是很有用,這樣可以將重復(fù)性計(jì)算任務(wù)轉(zhuǎn)換到服務(wù)器,提高數(shù)據(jù)庫(kù)應(yīng)用的性能。
Delphi中有兩個(gè)部件能操作遠(yuǎn)程數(shù)據(jù)庫(kù)服務(wù)器上的存儲(chǔ)過(guò)程:TQuery和TStoredProc。
1. TQuery的存儲(chǔ)過(guò)程編程
CSDEMO中演示用TQuery調(diào)用存儲(chǔ)過(guò)程的窗體是TFrmQueryProc。
TFrmQueryProc中有兩個(gè)TDBGrid 部件。DBGrid1顯示EmployeeTable中的數(shù)據(jù)。DBGrid2顯示Project表中的數(shù)據(jù)。使用存儲(chǔ)過(guò)程的TQuery部件名為EmployeeProjectsQuery,它的作用是建立Employee 表和Project 表的連接,以實(shí)現(xiàn)當(dāng)DBGrid1中記錄改變時(shí),DBGrid2中的數(shù)據(jù)作相應(yīng)的改變。具體的連接任務(wù)是由服務(wù)器上的存儲(chǔ)過(guò)程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)
該過(guò)程帶兩個(gè)參數(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語(yǔ)句中直接調(diào)用存儲(chǔ)過(guò)程。
下面是客戶端的程序:
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ǔ)句,雖非必須,但可以優(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;
該事件處理過(guò)程與EmployeeSource的OnDataChange屬性相聯(lián)。用于當(dāng)EmployeeTable數(shù)據(jù)記錄變化時(shí),修正存儲(chǔ)過(guò)程的輸入?yún)?shù),并執(zhí)行SQL語(yǔ)句。
相關(guān)推薦:2010年9月計(jì)算機(jī)等級(jí)考試試題及答案解析專題北京 | 天津 | 上海 | 江蘇 | 山東 |
安徽 | 浙江 | 江西 | 福建 | 深圳 |
廣東 | 河北 | 湖南 | 廣西 | 河南 |
海南 | 湖北 | 四川 | 重慶 | 云南 |
貴州 | 西藏 | 新疆 | 陜西 | 山西 |
寧夏 | 甘肅 | 青海 | 遼寧 | 吉林 |
黑龍江 | 內(nèi)蒙古 |