程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 多層數據庫開發二:單層和兩層的應用程序

多層數據庫開發二:單層和兩層的應用程序

編輯:Delphi
 第二章 單層和兩層的應用程序
  
  單層和兩層的數據庫應用程序相對來說比較簡單,應用程序和數據庫往往在同一個文件系統中,甚至就在同一個磁盤上。這兩種類型的數據庫應用程序都不太適合於在多用戶的環境下同時訪問同一個數據庫。
  對於單層的應用程序來說,Delphi 4提供了兩種獲得數據的方式,一種方式是通過BDE,另一種方式是通過文件。兩層的應用程序一般要使用BDE。
  2.1 基於BDE的應用程序
  由於BDE以及數據訪問構件處理了諸如讀數據、更新數據、記錄導航等細節,編寫一個兩層的應用程序與編寫一個單層的基於BDE的應用程序幾乎沒有什麼區別。
  發布基於BDE的應用程序時,必須同時發布BDE,這將使應用程序的字節數大大增加,同時也增加了發布、安裝的難度。但不管怎麼樣,BDE的作用還是無法替代的 。
  2.1.1 基於BDE的體系結構
  一個基於BDE的單層或兩層應用程序通常由這麼幾個部分組成:
  .用戶界面,其主要部件是數據控件;
  .一個或幾個數據集構件,用於從數據庫引入數據;
  .一個或幾個TDataSource構件,用於連接數據集與數據控件;
  .一個或幾個TDatabase構件(可選),用於控制事務。在兩層的應用程序中,TDatabase構件還能夠管理數據庫連接的持續性和要不要登錄;
  .一個或幾個TSession構件(可選),用在多線程的應用程序中管理數據庫的連接。
  圖2.1演示了基於BDE的應用程序的體系結構:圖2.1 基於BDE的體系結構 。
  2.1.2 理解數據庫和數據集
  數據庫與數據集是既有聯系又有區別的兩個概念。數據庫既包含了表格中的數據,而且還包含了表格本身的屬性、索引以及存儲過程等。而數據集主要用於引入表格中的數據。一個基於BDE的應用程序至少得有一個數據集構件。
  每個基於BDE的數據集構件都有一個公開的屬性叫DatabaseName,這個屬性用於指定要訪問的數據庫。
  DatabaseName屬性可以設為數據庫的BDE別名。一個別名不但代表了數據庫,也代表了數據庫的配置信息。不同類型的數據庫如Oracle、Sybase、Interbase、Paradox、dBASE,它們的配置信息也不同。用BDE Administration或SQL Explorer可以創建和管理BDE別名。
  對於Paradox或dBASE數據庫來說,DatabaseName屬性也可以設為表格所在的目錄。如果應用程序顯式地使用了TDatabase構件來連接數據庫,DatabaseName屬性可以設為應用程序專用的別名。
  2.1.3 使用會話期對象
  會話期對象(TSession)用在多線程的數據庫應用程序中管理數據庫的連接。會話期對象的作用主要體現在四個方面。
  管理BDE別名。可以用會話期對象創建新的別名、刪除別名、修改別名的 參數。默認情況下,用會話期對象創建和修改的別名只在本會話期是有效的,但是,您可以調用TSession的SaveConfigFile把別名永久地保存到BDE配置文件中,這樣,其他會話期和其他應用程序都可以使用這些別名。
  在兩層的數據庫應用程序中控制數據庫的連接。如果把TSession的KeepConnections屬性設為True,即使當前沒有數據集在活動狀態,也保持與數據庫的連接,這樣雖然浪費一點資源,但可以避免下次連接數據庫時再次登錄。在單層的數據庫應用程序中對Paradox和dBASE提供口令保護。既可以顯示一個對話框讓用戶輸入口令,也可以在程序中提供口令。如果計劃將單層的體系結構平滑地過渡到兩層或多層的體系結構,就必須設計一個人機界面,讓用戶輸入用戶名和口令,即使目前在單層的數據庫應用程序中用不著。
  指定BDE網絡控制文件PDOXUSRS.NET和存放私有文件的目錄。
  如果應用程序需要同時在幾個地方訪問同一個數據庫,就要用多個會話期對象來管理數據庫的連接。如果沒有這樣做的話,很可能會造成意想不到的後果。
  2.1.4 連接數據庫
  BDE中包含了不同類型的驅動程序用來連接不同類型的數據庫。Delphi4的Standard版本中包含了訪問本地數據庫的驅動程序如Paradox、dBASE、FoxPro和Access。Delphi 4的Professional版本除了訪問本地數據庫的驅動程序外,還包含了ODBC驅動程序,通過ODBC驅動程序可以訪問更廣泛的數據源。Delphi4的Client/Server版本和Enterprise版本還包含了SQL Links,可以訪問遠程大型數據庫,包括Interbase、Oracle、Sybase、Informix、Microsoft SQL Server和DB2。
  2.2 事 務
  一個事務實際上是一組動作,這些動作必須在表格被提交之前成功地執行。如果有某個動作執行失敗,所有的動作都將撤消(Undo),這樣能保證數據庫中不會有不一致的數據。
  默認情況下,BDE提供了隱含的事務處理能力,當數據集的某條記錄要寫到數據庫中時,BDE能保證不會有部分字段被更新而另一個部分字段沒有被更新的情況。
  在多用戶的環境下尤其是訪問SQL服務器的情況下,最好顯式地使用事務,因為隱含的事務處理能力畢竟是有限的,它會導致網絡開銷增大、應用程序性能下降。
  2.2.1 顯式地使用事務
  在基於BDE的數據庫應用程序中,要顯式地使用事務,有兩種方式,這兩種方式是互斥的,不能同時使用。
  通過TDatabase構件來連接數據庫,然後通過TDatabase的StartTransaction、Commit、Rollback、InTransaction和TransIsolation等屬性和方法來控制事務。這種方式的好處是,不需要依賴於特定的數據庫或服務器,程序的移植性較好,沒有多余的代碼。
  使用所謂的“Passthrough SQL”,即通過TQuery構件把SQL語句直接傳遞給遠程的SQL服務器或ODBC服務器。這種方式的好處是,可以直接使用服務器的事務管理能力,不過,這與特定的服務器有關,程序的移植性很難得到保證。
  單層的應用程序不能使用“Passthrough SQL”方式,只能用TDatabase構件來控制事務。而兩層的應用程序既可以使用TDatabase構件,也可以使用“Passthrough SQL”方式。
  2.2.2 TDatabase構件怎樣控制事務
  首先要調用StartTransaction開始一個事務。一旦啟動了一個事務,以後所有的讀寫操作均與事務有關,除非顯式地終止了事務。可以訪問TDatabase的InTransaction屬性,如果這個屬性返回True,表示現在已經開始了一個事務。此時,要檢索數據庫中的數據,取決於事務隔離級別(TransIsolation屬性)。
  啟動了一個事務後,就可以對數據庫進行讀寫操作,為了使修改後的數據永久地保存到數據庫中,應當調用TDatabase的Commit來提交。Commit通常放在Try...Except結構的Try部分調用,這樣,如果Commit沒有調用成功,還有機會調用Rollback。程序示例如下:
  Database1.StartTransaction;
  Try
   Table1.Edit;
   Table1.FieldByName('CustNo').AsInteger := 100;
   Table1.Post;Database1.Commit;
  Exception
    Database1.Rollback;
  End;
  2.2.3 TransIsolation屬性
  如果有多個事務同時在處理,並且訪問的是同一個表,這些事務彼此之間怎樣相互影響,是由TransIsolation屬性設置的事務隔離級別決定的。
  如果這個屬性設為tiDirtyRead,允許讀其他事務對數據庫尚未提交的修改。未提交的修改隨時有可能滾回,因此,這種情況下讀出來的數據是不可靠的。
  如果這個屬性設為tiReadCommitted,允許讀其他事務對數據庫已經提交的修改。如果這個屬性設為tiRepeatableRead,不允許讀其他事務對數據庫的修改。不同的服務器支持不同的事務隔離級別,如果TransIsolation屬性設置的事務隔離級別不被服務器所支持,BDE將自動降低事務隔離級別。
  注意:對Paradox、dBASE、Access和FoxPro等本地數據庫使用事務時,應當把TransIsolation屬性設為tiDirtyRead而不是默認值tiReadCommitted,否則,BDE會報錯。
  2.2.4 Passthrough SQL
  所謂“Passthrough SQL”,就是通過TQuery、TStoredProc或TUpdateSQL構件把SQL語句直接傳遞給遠程服務器,這些SQL語句中包含了對服務器事務處理功能的調用。
  要使用“Passthrough SQL”,必須滿足幾個條件:必須是Client/Server版本,並且已安裝了SQL Links驅動程序。正確配置了有關網絡協議。具有訪問遠程服務器的權限。必須用SQL Explorer把“SQLPASSTHRU MODE”參數設置為“NOT SHARED”。
  2.2.5 本地事務
  對於Paradox、dBASE、Access和FoxPro等本地數據庫來說,BDE也提供了事務處理能力,這稱為本地事務。
  從編程的角度看,本地事務與針對遠程數據庫的事務沒有什麼兩樣。不過,它的功能受到限制:
  .沒有崩潰自恢復功能
  .不支持數據定義語句。
  .不能針對臨時表進行事務。
  .對於Paradox表來說,必須建立了索引,否則,數據沒法回滾。
  .能夠被鎖定和修改的記錄數是有限的,Paradox限於255條記錄,dBASE限於100條記錄。
  .對於ASCII文本文件不能進行事務。
  .事務隔離級別(TransIsolation屬性)只能設為tiDirtyRead。
  2.2.6 緩存更新
  BDE提供了緩存更新技術。緩存更新的過程是這樣的:應用程序從數據庫檢索數據,對數據進行修改,實際上是在本地的緩存中,以後可以申請把緩存中的數據更新數據集。
  顯然,緩存更新技術能夠提高效率,減少網絡上的傳輸量。不過,緩存更新與事務還是有區別的。緩存中的數據只是對本應用程序是可見的,在申請更新之前,其他應用程序無法知道這些數據究竟作了哪些修改。所以,對於那些頻繁修改的數據不適用緩存更新技術,因為A用戶可能把數據改為10,而B用戶又把數據改為20,C用戶又把數據改為30,他們完全有可能同時向數據庫申請更新,這就會造成沖突。
  正是基於上述原因,數據集構件都有一個CachedUpdates屬性,讓您選擇要不要使用緩存更新技術。
  2.2.7 創建和重構表格
  在基於BDE的應用程序中,可以用TTable構件動態地創建一個表格,或者在一個已有的表格中建立一個索引。
  要創建一個表格,首先要建立字段定義(FieldDefs屬性),然後要建立索引定義(IndexDefs屬性),最後調用CreateTable。也可以在設計期用鼠標右鍵單擊TTable構件,在彈出的菜單中選擇“Create Table”命令。
  注意:如果要創建Oracle8類型的表格,Delphi 4目前還不能創建ADT字段、數組字段、引用字段和數據集字段。
  在運行期也可以改變表的結構(這稱為重構),這就需要調用BDE的一個API叫DbiDoRestructure。不過,如果僅僅要建立一個索引,調用AddIndex就可以了。
  在設計期,您可以使用Database Desktop創建和重構Paradox和dBASE表格,使用SQL Explorer可以創建和重構SQL表格。
  2.3 基於文件的單層數據庫應用程序
  基於文件的單層數據庫應用程序要用到TClientDataSet構件。TClientDataSet構件能夠從文件中存取數據,在內存中建立數據的一個副本,這樣,對數據的訪問和操作非常快,但數據的容量受內存的限制。
  2.3.1 TClientDataSet
  TClientDataSet不需要依賴於BDE,這意味著應用程序不必為BDE開銷內存,但數據本身需要內存。TClientDataSet只需要一個動態鏈接庫DBCLIENT.DLL的支持,因此,發布和安裝用TClientDataSet建立的程序是比較簡單的,省掉了BDE的配置和維護。
  正因為TClientDataSet沒有使用BDE,因此,基於文件的單層數據庫應用程序不適用於多用戶環境下使用。盡管TClientDataSet不支持BDE,但由於TClientDataSet是從TDataSet繼承下來的,因此,大多數能對TTable構件進行的操作也能對TClientDataSet構件進行,包括用標准的數據控件顯示TClientDataSet引入的數據。不必使用TDatabase構件,因為沒有數據庫需要管理,也不需要支持事務。也不必使用TSession構件,除非應用程序是多線程的。
   基於BDE的數據庫應用程序和基於文件的數據庫應用程序的區別在於,創建數據集的方式和存取數據的方式不同。
  2.3.2 在設計期創建數據集
  由於基於文件的單層數據庫應用程序使用的不是現成的數據庫,因此,它的首要任務就是創建一個數據集。創建了一個數據集後,可以把它保存到文件中,以後就可以從文件中取出來,不必再重建數據集。不過,保存數據集時,索引不會一起保存,因此,每次從文件中讀取數據集時,都得重新建立索引。
  可以在設計期用字段編輯器創建數據集,其一般步驟是:
  把一個TClientDataSet構件放到窗體上,單擊鼠標右鍵,在彈出的菜單中選擇“Fields Editor”命令,Delphi 4將打開字段編輯器,如圖2.2所示。
  圖2.2 字段編輯器
  在字段編輯器上單擊鼠標右鍵,在彈出的菜單中選擇“New Field”命令,Delphi 4將打開“New Field”對話框,如圖2.3所示
  在“Name”框內鍵入字段名,在“Type”框內選擇字段的數據類型,在“Size”框內設置字段長度,“Component”框將自動生成該字段的對象名。
   “Field Type”框用於指定新字段的生成類型(不是指字段的數據類型),可以選“Data”、“Calculated”、“Lookup”、“InternalCalc”和“Aggregate”。
  用字段編輯器創建的字段稱為永久字段。創建了永久字段後,用鼠標右鍵單擊TClientDataSet構件,在彈出的菜單中選擇“Create DataSet”命令,此時,Delphi 4將創建一個沒有記錄的空數據集。再次用鼠標右鍵單擊TClientDataSet構件,在彈出的菜單中選擇“Save To File”命令,把數據集保存到文件中,擴展名是.CDS。
  2.3.3 在運行期創建數據集
  要在運行期創建基於TClientDataSet的數據集,首先要建立字段定義和索引定義,這一點與創建基於TTable構件的數據集相似,不同的是,TClientDataSet沒有DatabaseName、TableName或TableType等屬性,因為TClientDataSet並不需要直接訪問數據庫。
  建立索引要用到IndexDefs屬性,這個屬性是TIndexDef對象,它有兩個屬性這裡詳細解釋一下:一是DescFields屬性,另一個是CaseInsFields屬性。
  如果TIndexDef的Options屬性中包含ixDescending元素,記錄按所有字段的降序排列。如果您想使記錄按部分字段的升序排列,按另一部分字段的降序排列,就要用到DescFields屬性。假設一個數據集有三個字段,分別叫Field1、Field2和Field3,如果把DescFields屬性設為“Field1;Field3”,表示按Field2的升序排列,按Field1和Field3的降序排列。
  CaseInsFields屬性的作用與DescFields屬性的作用類似,這裡不再贅述。
  建立了字段定義和索引定義後,就要調用CreateDataSet,程序示例如下:
  Procedure TForm1.FormCreate(Sender: TObject);
  Begin
   With ClientDataSet1 Do
  Begin
  {定義一個字段叫Field1}
  With FieldDefs.AddFieldDef Do
   Begin
   DataType := ftInteger;
   Name := 'Field1';
   End;
  {定義一個字段叫Field2}
  With FieldDefs.AddFieldDef Do
   BeginDataType := ftString;
   Size := 10;
   Name := 'Field2';
   End;
  {定義一個索引叫IntIndex}
  With IndexDefs.AddIndexDef Do
  Begin
    Fields := 'Field1';
    Name := 'IntIndex';
  End;
  CreateDataSet;
  End;
  End;
  2.3.4 基於一個已有的表格創建數據集
   如果要把一個基於BDE的應用程序轉換為單層的基於文件的應用程序,首先要把一個已有的表格轉換為TClientDataSet能識別的格式,操作步驟是這樣的:
  把一個TClientDataSet構件加到窗體上,單擊鼠標右鍵,在彈出的菜單中選擇“Assign Local Data”命令,彈出一個對話框,讓您從本地的基於BDE的數據集中引入數據,如圖2.4所示。
  選擇一個本地的數據集,然後單擊OK按鈕。
  再次用鼠標右鍵單擊TClientDataSet構件,在彈出的菜單中選擇“Save ToFile”命令。
  2.3.5 在文件中存取數據
  在單層的基於文件的應用程序中,TClientDataSet能自動維護一個數據變動情況的記錄。如果不准備恢復原來的數據,可以調用MergeChangeLog把變動情況合並在數據中。
  不過,即使把變動情況合並到數據中,數據仍然還在內存中,當應用程序關閉時,這些數據將丟失。因此,還必須調用SaveToFile把數據保存到文件中。
  SaveToFile只保存數據集的結構和數據,但不保存索引。因此,每次打開數據集時都要重建索引。
  要打開先前用SaveToFile保存的數據集,可以調用LoadFromFile。
  如果每次打開和保存的文件是不變的,也可以設置TClientDataSet的FileName屬性。當TClientDataSet的Active屬性設為True時,就會自動從指定的文件中讀取數據。當TClientDataSet的Active屬性設為False時,就會自動把數據保存到指定的文件中。
  2.3.6 公文包模式
  對於那些經常出差需要在路上辦公的人來說,出發之前往往要從數據庫中獲取某些數據,回來以後又要把修改後的數據寫回到數據庫中,這就是所謂的“公文包”模式。
  在多層體系結構的應用程序中,TClientDataSet一般是通過IProvider接口從應用服務器獲取數據。而要按“公文包”模式工作,就必須在文件中存取數據。
    “公文包”模式的關鍵是把數據保存到文件中,因此,客戶程序的用戶界面應當允許用戶從應用服務器檢索數據並保存到文件中,允許用戶從文件中調出數據並更新數據庫,而TClientDataSet的LoadFromFile和SaveToFile完全可以實現這些功能。
  “公文包”模式的另一個關鍵是客戶程序必須能夠判斷當前是否連接了應用服務器,換句話說,就是即使在離線的情況下,客戶程序也要能夠工作。
  2.3.7 平滑過渡到三層體系結構
  在兩層的體系結構中,一層是數據庫服務器,另一層是應用程序。應用程序在邏輯上又分為兩大部分,一是用戶界面,另一個是數據訪問鏈路。要把一個兩層的Client/Server應用程序平滑過渡在三層的Client/Server應用程序,一般采取這麼幾個步驟。
  第一步是創建一個新的項目作為應用服務器,然後把數據訪問鏈路部分放到應用服務器上。再把TDataSetProvider或TProvider構件加到應用服務器上,有一個數據集,就要加一個TDataSetProvider或TProvider構件。
  第二步是修改已有的兩層體系結構,把涉及到數據訪問鏈路的部分去掉,這樣,這個程序只剩下用戶界面部分。
  第三步是用TClientDataSet構件替換原來的數據集構件,然後加入一個或幾個MIDAS連接構件,如TDCOMConnection。
 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved