asp.net|oracle|緩衝|資料 為了建立可擴充、高效能的基於WEB的應用,ASP.NET提供一個稱為資料緩衝(Data Caching)的特性。資料緩衝支援將頻繁訪問的資料對象可程式化地存放在記憶體中。這一特性可擴充以廣泛地提高查詢Oracle資料庫中資料的ASP.NET應用的效能。本文講述一個策略,可用於採用Web Farm環境中的ASP.NET Web應用緩衝Oracle資料庫資料。這個技巧允許在記憶體中緩衝頻繁訪問的Oracle資料庫資料,而不是頻繁訪問資料庫來取資料。這可以協助避免到Oracle資料庫伺服器的不必要的遠路。進一步的,文章提出了一個保持快取資料以使其始終與Oracle資料同步的實現。
ASP.NET中的資料緩衝
ASP.NET中的資料緩衝由Cache類和System.Web.Caching命名空間中的CacheDependency類支援。Cache類提供向緩衝插入和從中取出資料的方法。CacheDependency類允許為緩衝中資料項目的指定其依賴項。當我們用Insert和Add方法將項目加入緩衝中,可以指定一個項目的到期(expiration)策略。我們可以用Insert方法的absoluteExpiration屬性來定義緩衝中一個項目的生命期。這個屬性允許你指定相應資料項目到期的準確時間。也可以使用slidingExpiration屬性來指定項目到期的流逝時間(基於它被訪問的時間)。一旦一個項目到期,它從緩衝中被清除。除非它再次被加入緩衝中,否則再試圖訪問,將返回一個空值。
設定緩衝依賴
ASP.NET使我們可以基於一個外部檔案、目錄或另一個快取項目來定義一個快取項目的依賴,即所謂檔案依賴與鍵依賴。若一個依賴項改變,快取項目自動失效並被從緩衝中清除。當相應的資料來源改變時,我們可以用這種方法來從緩衝中刪除項目。例如,若我們的應用從一個XML檔案中取資料並顯示在一個表格(grid)中,我們可以把檔案中的資料存放到緩衝中,並設定緩衝依賴於那個XML檔案。當XML檔案被更新,資料項目就從緩衝中被清除出去。這一事件發生時,應用重新讀入XML檔案,最新的資料項目副本被再一次插入緩衝中。進一步的,回調事件處理器可被設定為一個監聽者,當快取項目被刪除時得到通知。這使得我們不需要反覆輪詢緩衝來確定資料項目是否已無效。
Oracle資料庫上的ASP.NET緩衝依賴
現在考慮這樣一個情景:資料存放於Oracle資料庫中,一個ASP.NET應用通過ADO.NET來訪問。進一步,我們假設資料庫表中的資料一般是靜態,並被這個Web應用頻繁訪問。表上的DML操作很少而對資料有很多Select。這種情況是資料緩衝技術的理想應用。但不幸的是,ASP.NET並不允許設定一個快取項目依賴於存放在資料庫表中的資料。進一步,現實世界中,基於Web的系統,Web伺服器和Oracle資料庫伺服器總是會運行在不同的機器上,使得快取無效判定操作更有挑戰性。另外,多數基於Web的應用採用Web farms,同一個應用的執行個體在不同的Web伺服器上跑以負載平衡。這種情況使得資料庫緩衝問題稍稍複雜一些。
為了進一步研究上述問題的解決方案,我們舉一個Web應用的例子來說明如何?。例子中,我們使用VB.NET實現的ASP.NET應用,通過Oracle Data Provider for .NET (ODP)來訪問 Oracle 9i資料庫。
這個例子使用Oracle資料庫中一個名為Employee的表。我們為該表上insert, update, delete設定觸發器。這些觸發器調用一個封裝了一個Java預存程序的PL/SQL函數。這個Java預存程序負責更新緩衝依賴的檔案。
ASP.NET Tier的VB.NET實現
我們設計了含一個回調方法的監聽類來處理快取項目無效時的通知。這個回調方法RemovedCallback用一個代理(delegate)函數來註冊。回調方法onRemove的聲明必須與CacheItemRemovedCallback代理聲明又相同的簽名。
Dim onRemove As CacheItemRemovedCallback = Nothing
onRemove = New CacheItemRemovedCallback(AddressOf RemovedCallback)
監聽事件處理方法RemovedCallback負責處理資料庫觸發器的通知,其定義如下。若快取項目失效,可用資料庫方法調用getRecordFromdatabase()從資料庫取出資料。參數”key”指從緩衝中刪除的項的索引位置。參數”value”指從緩衝中刪除的資料對象。參數"CacheItemRemovedReason"指從緩衝中刪除資料項目的原因。
PublicSub RemovedCallback(ByVal key AsString, ByVal value AsObject, ByVal reason As CacheItemRemovedReason)
Dim Source As DataView
Source = getRecordFromdatabase()
Cache.Insert("employeeTable ", Source, New
System.Web.Caching.CacheDependency("d:\download\tblemployee.txt"),
Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
CacheItemPriority.Normal, onRemove)
EndSub
方法getRecordFromdatabase()負責查詢資料庫表Employee並返回一個DataView對象引用。它使用一個名為getEmployee的預存程序來抽象從Employee表中取資料的SQL。這個方法有一個名為p_empid的參數,表示Employee的主鍵。
PublicFunction getRecordFromdatabase (ByVal p_empid As Int32) As DataView
Dim con As OracleConnection = Nothing
Dim cmd As OracleCommand = Nothing
Dim ds As DataSet = Nothing
Try
con = getDatabaseConnection( "UserId=scott;Password=tiger;Data Source=testingdb;")
cmd = New OracleCommand("Administrator.getEmployee", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add(New OracleParameter("employeeId", OracleDbType.Int64)).Value = p_empid
Dim param AsNew OracleParameter("RC1", OracleDbType.RefCursor)
cmd.Parameters.Add(param).Direction = ParameterDirection.Output
Dim myCommand AsNew OracleDataAdapter(cmd)
ds = New DataSet
myCommand.Fill(ds)
Dim table As DataTable = ds.Tables(0)
Dim index As Int32 = table.Rows.Count
Return ds.Tables(0).DefaultView
Catch ex As Exception
ThrowNew Exception("Exception in Database Tier Method getRecordFromdatabase () " + ex.Message, ex)
Finally
Try
cmd.Dispose()
Catch ex As Exception
Finally
cmd = Nothing
EndTry
Try
con.Close()
Catch ex As Exception
Finally
con = Nothing
EndTry
EndTry
EndFunction
函數getDatabaseConnection接受一個連接字串(connection stirng)為參數,返回一個OracleConnection對象引用。
PublicFunction getDatabaseConnection(ByVal strconnection as string) As OracleConnection
Dim con As Oracle.DataAccess.Client.OracleConnection = Nothing
Try
con = New Oracle.DataAccess.Client.OracleConnection
con.ConnectionString = strconnection
con.Open()
Return con
Catch ex As Exception
ThrowNew Exception("Exception in Database Tier Method getOracleConnection() " + ex.Message, ex)
EndTry
EndFunction
Oracle資料庫Tier實現
定義Employee表上DML事件的觸發器體如下。這個觸發器簡單的調用一個PL/SQL包裹函數來更新名為tblemployee.txt的作業系統檔案。檔案副本在兩台機器(機器1和機器2)上更新。兩台機器運行同一個Web應用的不同執行個體來均衡負載。這裡administrator指Oracle資料庫的方案(schema)對象所有者。
begin
administrator.plfile('machine1\\download\\ tblemployee.txt');
administrator.plfile('machine2\\download\\ tblemployee.txt');
end;
為更新緩衝依賴檔案,我們需要寫一個C函數或Java預存程序。我們的例子中選擇了Java預存程序,因為Oracle資料庫伺服器有一個內建的JVM,使得書寫Java預存程序很方便。必須有足夠的記憶體配置給Oracle執行個體的系統全域區(SGA)中的Java池。靜態方法updateFile接受一個絕對路徑作為參數,並在合適的目錄中建立緩衝依賴檔案。若檔案已經存在,則先刪除然後建立。
import java.io.*;
public class UpdFile {public static void updateFile(String filename)
{
try {
File f = new File(filename);
f.delete();
f.createNewFile();
}
catch (IOException e)
{
// log exception
}
};
PL/SQL包裹實現如下。包裹函數以檔案名稱為參數,調用Java預存程序中updateFile方法。
(p_filename IN VARCHAR2)
AS LANGUAGE JAVA
NAME 'UpdFile.updateFile (java.lang.String)';
Web Farm部署中的Oracle資料緩衝
正如我們討論的例子中所示,Web伺服器1和機器2構成了一個Web Farm來為我們的Web應用提供負載平衡。每台機器運行同一個Web應用的一個執行個體。在這個情況下,每個執行個體可以擁有自己的存放在Cache對象中的快取資料副本。當Employee表改變,相應的資料庫觸發器更新兩台機器上的檔案tblemployee.txt。每個執行個體都指定一個到tblemployee.txt的緩衝依賴,Web Farm的兩個執行個體都可以正確更新,使得兩個執行個體上的資料緩衝可以和資料庫表Employee保持同步。
結論
資料緩衝是最佳化Oracle資料庫上ASP.NET應用的有效技巧。儘管ASP.NET不允許設定緩衝的資料庫依賴,Oracle觸發器協同Java預存程序可以擴充ASP.NET緩衝的威力從而允許Oracle資料庫緩衝。這個技巧也可以適用於Web Farm部署。