为ASP.NET应用缓存Oracle数据

简介:

为了创建可扩展、高性能的基于WEB的应用,ASP.NET提供一个称为数据缓存(DataCaching)的特性。数据缓存支持将频繁访问的数据对象可编程地存放在内存中。这一特性可扩展以广泛地提高查询Oracle数据库中数据的ASP.NET应用的性能。本文讲述一个策略,可用于采用WebFarm环境中的ASP.NETWeb应用缓存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的应用采用Webfarms,同一个应用的实例在不同的Web服务器上跑以负载均衡。这种情况使得数据库缓存问题稍稍复杂一些。

为了进一步研究上述问题的解决方案,我们举一个Web应用的例子来说明如何实现。例子中,我们使用VB.NET实现的ASP.NET应用,通过OracleDataProviderfor.NET(ODP)来访问Oracle9i数据库。

这个例子使用Oracle数据库中一个名为Employee的表。我们为该表上insert,update,delete设定触发器。这些触发器调用一个封装了一个Java存储过程的PL/SQL函数。这个Java存储过程负责更新缓存依赖的文件。

ASP.NETTier的VB.NET实现

我们设计了含一个回调方法的监听类来处理缓存项无效时的通知。这个回调方法RemovedCallback用一个代理(delegate)函数来注册。回调方法onRemove的声明必须与CacheItemRemovedCallback代理声明又相同的签名。

DimonRemoveAsCacheItemRemovedCallback=Nothing

onRemove=NewCacheItemRemovedCallback(AddressOfRemovedCallback)

监听事件处理方法RemovedCallback负责处理数据库触发器的通知,其定义如下。若缓存项失效,可用数据库方法调用getRecordFromdatabase()从数据库取出数据。参数”key”指从缓存中删除的项的索引位置。参数”value”指从缓存中删除的数据对象。参数"CacheItemRemovedReason"指从缓存中删除数据项的原因。

PublicSubRemovedCallback(ByValkeyAsString,ByValvalueAsObject,ByValreasonAsCacheItemRemovedReason)

DimSourceAsDataView

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的主键。

PublicFunctiongetRecordFromdatabase(ByValp_empidAsInt32)AsDataView

DimconAsOracleConnection=Nothing

DimcmdAsOracleCommand=Nothing

DimdsAsDataSet=Nothing

Try

con=getDatabaseConnection("UserId=scott;Password=tiger;DataSource=testingdb;")

cmd=NewOracleCommand("Administrator.getEmployee",con)

cmd.CommandType=CommandType.StoredProcedure

cmd.Parameters.Add(NewOracleParameter("employeeId",OracleDbType.Int64)).Value=p_empid

DimparamAsNewOracleParameter("RC1",OracleDbType.RefCursor)

cmd.Parameters.Add(param).Direction=ParameterDirection.Output

DimmyCommandAsNewOracleDataAdapter(cmd)

ds=NewDataSet

myCommand.Fill(ds)

DimtableAsDataTable=ds.Tables(0)

DimindexAsInt32=table.Rows.Count

Returnds.Tables(0).DefaultView

CatchexAsException

ThrowNewException("ExceptioninDatabaseTierMethodgetRecordFromdatabase()"+ex.Message,ex)

Finally

Try

cmd.Dispose()

CatchexAsException

Finally

cmd=Nothing

EndTry

Try

con.Close()

CatchexAsException

Finally

con=Nothing

EndTry

EndTry

EndFunction

函数getDatabaseConnection接受一个连接字符串(connectionstirng)为参数,返回一个OracleConnection对象引用。

PublicFunctiongetDatabaseConnection(ByValstrconnectionasstring)AsOracleConnection

DimconAsOracle.DataAccess.Client.OracleConnection=Nothing

Try

con=NewOracle.DataAccess.Client.OracleConnection

con.ConnectionString=strconnection

con.Open()

Returncon

CatchexAsException

ThrowNewException("ExceptioninDatabaseTierMethodgetOracleConnection()"+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接受一个绝对路径作为参数,并在合适的目录中创建缓存依赖文件。若文件已经存在,则先删除然后创建。

importjava.io.*;

publicclassUpdFile{publicstaticvoidupdateFile(Stringfilename)

{

try{

Filef=newFile(filename);

f.delete();

f.createNewFile();

}

catch(IOExceptione)

{

//logexception

}

};

PL/SQL包裹实现如下。包裹函数以文件名为参数,调用Java存储过程中updateFile方法。

(p_filenameINVARCHAR2)

ASLANGUAGEJAVA

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

WebFarm部署中的Oracle数据缓存

正如我们讨论的例子中所示,Web服务器1和机器2构成了一个WebFarm来为我们的Web应用提供负载均衡。每台机器运行同一个Web应用的一个实例。在这个情况下,每个实例可以拥有自己的存放在Cache对象中的缓存数据副本。当Employee表改变,相应的数据库触发器更新两台机器上的文件tblemployee.txt。每个实例都指定一个到tblemployee.txt的缓存依赖,WebFarm的两个实例都可以正确更新,使得两个实例上的数据缓存可以和数据库表Employee保持同步。

结论

数据缓存是优化Oracle数据库上ASP.NET应用的有效技巧。尽管ASP.NET不允许设定缓存的数据库依赖,Oracle触发器协同Java存储过程可以扩展ASP.NET缓存的威力从而允许Oracle数据库缓存。这个技巧也可以适用于WebFarm部署。

目录
相关文章
|
2月前
|
开发框架 Oracle 关系型数据库
ASP.NET实验室LIS系统源码 Oracle数据库
LIS是HIS的一个组成部分,通过与HIS的无缝连接可以共享HIS中的信息资源,使检验科能与门诊部、住院部、财务科和临床科室等全院各部门之间协同工作。 
35 4
|
2月前
|
SQL Oracle 关系型数据库
Oracle 将表中的数据查出更改某一字段的值后再插入该表
Oracle 将表中的数据查出更改某一字段的值后再插入该表
31 2
|
2月前
|
存储 Oracle NoSQL
Oracle 表空间、数据文件、schema的关系
Oracle 表空间、数据文件、schema的关系
32 2
|
2月前
|
SQL Oracle 关系型数据库
Oracle查询优化-查询只包含数字或字母的数据
【2月更文挑战第4天】【2月更文挑战第10篇】查询只包含数字或字母的数据
82 1
|
3月前
|
Oracle 关系型数据库
Oracle查询优化-从表中随机返回N条数据
【1月更文挑战第2天】【1月更文挑战第5篇】有些场景需要抽验数据,例如为了防止做假或者抽检行为,就需要随机抽查。
42 0
|
4月前
|
存储 缓存 分布式计算
亿级数据如何分钟级别写入缓存?
亿级数据如何分钟级别写入缓存?
29 0
|
3月前
|
Oracle 关系型数据库 数据库
Oracle查询优化-复制表的定义及数据
【1月更文挑战第5天】【1月更文挑战第14篇】在Oracle数据库中,复制表定义和复制表数据是两个常见的操作。
50 1
|
3月前
|
Oracle 关系型数据库 Java
这个错误是由于在尝试从 Oracle 数据库的 socket 中读取数据时,没有更多的数据可供读取
这个错误是由于在尝试从 Oracle 数据库的 socket 中读取数据时,没有更多的数据可供读取
50 2
|
1月前
|
SQL Oracle 关系型数据库
Oracle insert数据时字符串中有‘单引号问题
Oracle insert数据时字符串中有‘单引号问题
|
1月前
|
缓存 NoSQL Java
【九】springboot整合redis实现启动服务时热点数据保存在全局和缓存
【九】springboot整合redis实现启动服务时热点数据保存在全局和缓存
39 0

推荐镜像

更多