為了創建可擴展高性能的基於WEB的應用ASPNET提供一個稱為數據緩存(Data Caching)的特性數據緩存支持將頻繁訪問的數據對象可編程地存放在內存中這一特性可擴展以廣泛地提高查詢Oracle數據庫中數據的ASPNET應用的性能本文講述一個策略可用於采用Web Farm環境中的ASPNET Web應用緩存Oracle數據庫數據這個技巧允許在內存中緩存頻繁訪問的Oracle數據庫數據而不是頻繁訪問數據庫來取數據這可以幫助避免到Oracle數據庫服務器的不必要的遠路進一步的文章提出了一個保持緩存數據以使其始終與Oracle數據同步的實現
ASPNET中的數據緩存
ASPNET中的數據緩存由Cache類和SystemWebCaching命名空間中的CacheDependency類支持Cache類提供向緩存插入和從中取出數據的方法CacheDependency類允許為緩存中數據項的指定其依賴項當我們用Insert和Add方法將項目加入緩存中可以指定一個項目的過期(expiration)策略我們可以用Insert方法的absoluteExpiration屬性來定義緩存中一個項目的生命期這個屬性允許你指定相應數據項過期的准確時間也可以使用slidingExpiration屬性來指定項目過期的流逝時間(基於它被訪問的時間)一旦一個項目過期它從緩存中被清除除非它再次被加入緩存中否則再試圖訪問將返回一個空值
設定緩存依賴
ASPNET使我們可以基於一個外部文件目錄或另一個緩存項來定義一個緩存項的依賴即所謂文件依賴與鍵依賴若一個依賴項改變緩存項自動失效並被從緩存中清除當相應的數據源改變時我們可以用這種方法來從緩存中刪除項目例如若我們的應用從一個XML文件中取數據並顯示在一個表格(grid)中我們可以把文件中的數據存放到緩存中並設定緩存依賴於那個XML文件當XML文件被更新數據項就從緩存中被清除出去這一事件發生時應用重新讀入XML文件最新的數據項副本被再一次插入緩存中進一步的回調事件處理器可被設定為一個監聽者當緩存項被刪除時得到通知這使得我們不需要反復輪詢緩存來確定數據項是否已無效
Oracle數據庫上的ASPNET緩存依賴
現在考慮這樣一個情景數據存放於Oracle數據庫中一個ASPNET應用通過ADONET來訪問進一步我們假設數據庫表中的數據一般是靜態的並被這個Web應用頻繁訪問表上的DML操作很少而對數據有很多Select這種情況是數據緩存技術的理想應用但不幸的是ASPNET並不允許設定一個緩存項依賴於存放在數據庫表中的數據進一步現實世界中基於Web的系統Web服務器和Oracle數據庫服務器總是會運行在不同的機器上使得緩存無效操作更有挑戰性另外多數基於Web的應用采用Web farms同一個應用的實例在不同的Web服務器上跑以負載均衡這種情況使得數據庫緩存問題稍稍復雜一些
為了進一步研究上述問題的解決方案我們舉一個Web應用的例子來說明如何實現例子中我們使用VBNET實現的ASPNET應用通過Oracle Data Provider for NET (ODP)來訪問 Oracle i數據庫
這個例子使用Oracle數據庫中一個名為Employee的表我們為該表上insert update delete設定觸發器這些觸發器調用一個封裝了一個Java存儲過程的PL/SQL函數這個Java存儲過程負責更新緩存依賴的文件
ASPNET Tier的VBNET實現
我們設計了含一個回調方法的監聽類來處理緩存項無效時的通知這個回調方法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()
CacheInsert(employeeTable Source New
SystemWebCachingCacheDependency(d\download\tblemployeetxt)
CacheNoAbsoluteExpiration CacheNoSlidingExpiration
CacheItemPriorityNormal onRemove)
EndSub
方法getRecordFromdatabase()負責查詢數據庫表Employee並返回一個DataView對象引用它使用一個名為getEmployee的存儲過程來抽象從Employee表中取數據的SQL這個方法有一個名為p_empid的參數表示Employee的主鍵
以下是引用片段
PublicFunction getRecordFromdatabase (ByVal p_empid As Int) As DataView
Dim con As OracleConnection = Nothing
Dim cmd As OracleCommand = Nothing
Dim ds As DataSet = Nothing
Try
con = getDatabaseConnection( UserId=scottPassword=tigerData Source=testingdb)
cmd = New OracleCommand(AdministratorgetEmployee con)
cmdCommandType = CommandTypeStoredProcedure
cmdParametersAdd(New OracleParameter(employeeId OracleDbTypeInt))Value = p_empid
Dim param AsNew OracleParameter(RC OracleDbTypeRefCursor)
cmdParametersAdd(param)Direction = ParameterDirectionOutput
Dim myCommand AsNew OracleDataAdapter(cmd)
ds = New DataSet
myCommandFill(ds)
Dim table As DataTable = dsTables()
Dim index As Int = tableRowsCount
Return dsTables()DefaultView
Catch ex As Exception
ThrowNew Exception(Exception in Database Tier Method getRecordFromdatabase () + exMessage ex)
Finally
Try
cmdDispose()
Catch ex As Exception
Finally
cmd = Nothing
EndTry
Try
conClose()
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 OracleDataAccessClientOracleConnection = Nothing
Try
con = New OracleDataAccessClientOracleConnection
conConnectionString = strconnection
conOpen()
Return con
Catch ex As Exception
ThrowNew Exception(Exception in Database Tier Method getOracleConnection()
+ exMessage ex)
EndTry
EndFunction
Oracle數據庫Tier實現
定義Employee表上DML事件的觸發器體如下這個觸發器簡單的調用一個PL/SQL包裹函數來更新名為tblemployeetxt的操作系統文件文件副本在兩台機器(機器和機器)上更新兩台機器運行同一個Web應用的不同實例來均衡負載這裡administrator指Oracle數據庫的方案(schema)對象所有者
begin administratorplfile(machine\\download\\ tblemployeetxt) administratorplfile(machine\\download\\ tblemployeetxt)end
為更新緩存依賴文件我們需要寫一個C函數或Java存儲過程我們的例子中選擇了Java存儲過程因為Oracle數據庫服務器有一個內置的JVM使得書寫Java存儲過程很方便必須有足夠的內存分配給Oracle實例的系統全局區(SGA)中的Java池靜態方法updateFile接受一個絕對路徑作為參數並在合適的目錄中創建緩存依賴文件若文件已經存在則先刪除然後創建
import javaio*public class UpdFile {public static void updateFile(String filename) { try { File f = new File(filename) fdelete() fcreateNewFile() } catch (IOException e) { // log exception }}
NPL/SQL包裹實現如下包裹函數以文件名為參數調用Java存儲過程中updateFile方法
(p_filename IN VARCHAR)
AS LANGUAGE JAVA
NAME UpdFileupdateFile (javalangString)
Web Farm部署中的Oracle數據緩存
正如我們討論的例子中所示Web服務器和機器構成了一個Web Farm來為我們的Web應用提供負載均衡每台機器運行同一個Web應用的一個實例在這個情況下每個實例可以擁有自己的存放在Cache對象中的緩存數據副本當Employee表改變相應的數據庫觸發器更新兩台機器上的文件tblemployeetxt每個實例都指定一個到tblemployeetxt的緩存依賴Web Farm的兩個實例都可以正確更新使得兩個實例上的數據緩存可以和數據庫表Employee保持同步
結論
數據緩存是優化Oracle數據庫上ASPNET應用的有效技巧盡管ASPNET不允許設定緩存的數據庫依賴Oracle觸發器協同Java存儲過程可以擴展ASPNET緩存的威力從而允許Oracle數據庫緩存這個技巧也可以適用於Web Farm部署
From:http://tw.wingwit.com/Article/program/net/201311/11872.html