當前位置:首頁>>軟件教程>>新聞內容  
為ASP.NET應用緩存Oracle數(shù)據(jù)
作者:Narayan Veeramani(原作),ern(翻譯) 發(fā)布時間:2004-1-16 15:29:26 | 【字體:

為了創(chuàng)建可擴展、高性能的基于WEB的應用,ASP.NET提供一個稱為數(shù)據(jù)緩存(Data Caching)的特性。數(shù)據(jù)緩存支持將頻繁訪問的數(shù)據(jù)對象可編程地存放在內存中。這一特性可擴展以廣泛地提高查詢Oracle數(shù)據(jù)庫中數(shù)據(jù)的ASP.NET應用的性能。本文講述一個策略,可用于采用Web Farm環(huán)境中的ASP.NET Web應用緩存Oracle數(shù)據(jù)庫數(shù)據(jù)。這個技巧允許在內存中緩存頻繁訪問的Oracle數(shù)據(jù)庫數(shù)據(jù),而不是頻繁訪問數(shù)據(jù)庫來取數(shù)據(jù)。這可以幫助避免到Oracle數(shù)據(jù)庫服務器的不必要的遠路。進一步的,文章提出了一個保持緩存數(shù)據(jù)以使其始終與Oracle數(shù)據(jù)同步的實現(xiàn)。

ASP.NET中的數(shù)據(jù)緩存

ASP.NET中的數(shù)據(jù)緩存由Cache類和System.Web.Caching命名空間中的CacheDependency類支持。Cache類提供向緩存插入和從中取出數(shù)據(jù)的方法。CacheDependency類允許為緩存中數(shù)據(jù)項的指定其依賴項。當我們用InsertAdd方法將項目加入緩存中,可以指定一個項目的過期(expiration)策略。我們可以用Insert方法的absoluteExpiration屬性來定義緩存中一個項目的生命期。這個屬性允許你指定相應數(shù)據(jù)項過期的準確時間。也可以使用slidingExpiration屬性來指定項目過期的流逝時間(基于它被訪問的時間)。一旦一個項目過期,它從緩存中被清除。除非它再次被加入緩存中,否則再試圖訪問,將返回一個空值。

設定緩存依賴

ASP.NET使我們可以基于一個外部文件、目錄或另一個緩存項來定義一個緩存項的依賴,即所謂文件依賴與鍵依賴。若一個依賴項改變,緩存項自動失效并被從緩存中清除。當相應的數(shù)據(jù)源改變時,我們可以用這種方法來從緩存中刪除項目。例如,若我們的應用從一個XML文件中取數(shù)據(jù)并顯示在一個表格(grid)中,我們可以把文件中的數(shù)據(jù)存放到緩存中,并設定緩存依賴于那個XML文件。當XML文件被更新,數(shù)據(jù)項就從緩存中被清除出去。這一事件發(fā)生時,應用重新讀入XML文件,最新的數(shù)據(jù)項副本被再一次插入緩存中。進一步的,回調事件處理器可被設定為一個監(jiān)聽者,當緩存項被刪除時得到通知。這使得我們不需要反復輪詢緩存來確定數(shù)據(jù)項是否已無效。

Oracle數(shù)據(jù)庫上的ASP.NET緩存依賴

現(xiàn)在考慮這樣一個情景:數(shù)據(jù)存放于Oracle數(shù)據(jù)庫中,一個ASP.NET應用通過ADO.NET來訪問。進一步,我們假設數(shù)據(jù)庫表中的數(shù)據(jù)一般是靜態(tài)的,并被這個Web應用頻繁訪問。表上的DML操作很少而對數(shù)據(jù)有很多Select。這種情況是數(shù)據(jù)緩存技術的理想應用。但不幸的是,ASP.NET并不允許設定一個緩存項依賴于存放在數(shù)據(jù)庫表中的數(shù)據(jù)。進一步,現(xiàn)實世界中,基于Web的系統(tǒng),Web服務器和Oracle數(shù)據(jù)庫服務器總是會運行在不同的機器上,使得緩存無效操作更有挑戰(zhàn)性。另外,多數(shù)基于Web的應用采用Web farms,同一個應用的實例在不同的Web服務器上跑以負載均衡。這種情況使得數(shù)據(jù)庫緩存問題稍稍復雜一些。

為了進一步研究上述問題的解決方案,我們舉一個Web應用的例子來說明如何實現(xiàn)。例子中,我們使用VB.NET實現(xiàn)的ASP.NET應用,通過Oracle Data Provider for .NET (ODP)來訪問 Oracle 9i數(shù)據(jù)庫。

這個例子使用Oracle數(shù)據(jù)庫中一個名為Employee的表。我們?yōu)樵摫砩?/SPAN>insert, update, delete設定觸發(fā)器。這些觸發(fā)器調用一個封裝了一個Java存儲過程的PL/SQL函數(shù)。這個Java存儲過程負責更新緩存依賴的文件。

ASP.NET TierVB.NET實現(xiàn)

我們設計了含一個回調方法的監(jiān)聽類來處理緩存項無效時的通知。這個回調方法RemovedCallback用一個代理(delegate)函數(shù)來注冊;卣{方法onRemove的聲明必須與CacheItemRemovedCallback代理聲明又相同的簽名。

   Dim onRemove As CacheItemRemovedCallback = Nothing

   onRemove = New CacheItemRemovedCallback(AddressOf RemovedCallback)

       監(jiān)聽事件處理方法RemovedCallback負責處理數(shù)據(jù)庫觸發(fā)器的通知,其定義如下。若緩存項失效,可用數(shù)據(jù)庫方法調用getRecordFromdatabase()從數(shù)據(jù)庫取出數(shù)據(jù)。參數(shù)”key”指從緩存中刪除的項的索引位置。參數(shù)”value”指從緩存中刪除的數(shù)據(jù)對象。參數(shù)"CacheItemRemovedReason"指從緩存中刪除數(shù)據(jù)項的原因。

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()負責查詢數(shù)據(jù)庫表Employee并返回一個DataView對象引用。它使用一個名為getEmployee的存儲過程來抽象從Employee表中取數(shù)據(jù)的SQL。這個方法有一個名為p_empid的參數(shù),表示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

函數(shù)getDatabaseConnection接受一個連接字符串(connection stirng)為參數(shù),返回一個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數(shù)據(jù)庫Tier實現(xiàn)

       定義Employee表上DML事件的觸發(fā)器體如下。這個觸發(fā)器簡單的調用一個PL/SQL包裹函數(shù)來更新名為tblemployee.txt的操作系統(tǒng)文件。文件副本在兩臺機器(機器1和機器2)上更新。兩臺機器運行同一個Web應用的不同實例來均衡負載。這里administratorOracle數(shù)據(jù)庫的方案(schema)對象所有者。

begin

   administrator.plfile('machine1\\download\\ tblemployee.txt');

   administrator.plfile('machine2\\download\\ tblemployee.txt');

end;

       為更新緩存依賴文件,我們需要寫一個C函數(shù)或Java存儲過程。我們的例子中選擇了Java存儲過程,因為Oracle數(shù)據(jù)庫服務器有一個內置的JVM,使得書寫Java存儲過程很方便。必須有足夠的內存分配給Oracle實例的系統(tǒng)全局區(qū)(SGA)中的Java池。靜態(tài)方法updateFile接受一個絕對路徑作為參數(shù),并在合適的目錄中創(chuàng)建緩存依賴文件。若文件已經(jīng)存在,則先刪除然后創(chuàng)建。

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包裹實現(xiàn)如下。包裹函數(shù)以文件名為參數(shù),調用Java存儲過程中updateFile方法。

(p_filename IN VARCHAR2)

AS LANGUAGE JAVA

NAME 'UpdFile.updateFile (java.lang.String)';

Web Farm部署中的Oracle數(shù)據(jù)緩存

正如我們討論的例子中所示,Web服務器1和機器2構成了一個Web Farm來為我們的Web應用提供負載均衡。每臺機器運行同一個Web應用的一個實例。在這個情況下,每個實例可以擁有自己的存放在Cache對象中的緩存數(shù)據(jù)副本。當Employee表改變,相應的數(shù)據(jù)庫觸發(fā)器更新兩臺機器上的文件tblemployee.txt。每個實例都指定一個到tblemployee.txt的緩存依賴,Web Farm的兩個實例都可以正確更新,使得兩個實例上的數(shù)據(jù)緩存可以和數(shù)據(jù)庫表Employee保持同步。

結論

數(shù)據(jù)緩存是優(yōu)化Oracle數(shù)據(jù)庫上ASP.NET應用的有效技巧。盡管ASP.NET不允許設定緩存的數(shù)據(jù)庫依賴,Oracle觸發(fā)器協(xié)同Java存儲過程可以擴展ASP.NET緩存的威力從而允許Oracle數(shù)據(jù)庫緩存。這個技巧也可以適用于Web Farm部署。


文章來源:西部E網(wǎng)
 放生
 愚愛
 夠愛
 觸電
 白狐
 葬愛
 光榮
 畫心
 火花
 稻香
 小酒窩
 下雨天
 右手邊
 安靜了
 魔杰座
 你不像她
 邊做邊愛
 擦肩而過
 我的答鈴
 懷念過去
 等一分鐘
 放手去愛
 冰河時代
 你的承諾
 自由飛翔
 原諒我一次
 吻的太逼真
 左眼皮跳跳
 做你的愛人
 一定要愛你
 飛向別人的床
 愛上別人的人
 感動天感動地
 心在跳情在燒
 玫瑰花的葬禮
 有沒有人告訴你
 即使知道要見面
 愛上你是一個錯
 最后一次的溫柔
 愛上你是我的錯
 怎么會狠心傷害我
 不是因為寂寞才想
 親愛的那不是愛情
 難道愛一個人有錯
 寂寞的時候說愛我