标签存档: Cache

[ASP] 《在JScript中使用缓存技术》补遗

《在JScript中使用缓存技术》一文中,在JScript中实现了基于Application.StaticObjects的缓存技术,并且实现一个类用于缓存的操作,但在实际使用过程中仍需要注意一些问题。

在JScript的函数中,如果参数类型是number或者string,那么是按值传递的,但如果是object,那么就是按引用传递了。另外,数组在JScript中也是作为一个特殊的对象对待,因此,数组的类型也是object,同样是按引用传递的。

使用xbsCache类进行保存和获取数据操作即put和get时,不管是按值还是按引用,都没有问题,但是在使用过程中,对数据操作的效果由数据类型不同而不同。

如果数据是number或string类型的,那么在get数据时,返回值是按值的,也就是说,我们得到的数据是缓存数据的一份copy,对变量的操作并不会影响到缓存中的数据,例:

  • // code by xujiwei
  • // from www.xujiwei.cn
  • var myname=”my name is xujiwei”;
  • xbsCache.put(“name”,myname);
  • // 从缓存中获取name,值为”my name is xujiwei”
  • var myname2=xbsCache.get(“name”);
  • // 给myname2赋值”xujiwei”
  • myname2=”xujiwei”;
  • // 从缓存中获取name,值仍为”my name is xujiwei”
  • var myname3=xbsCache.get(“name”);

但是在数据类型为object的情况下,我们就需要注意,在从缓存中获取数据之后,我们得到的只是一个指向缓存数据的引用而已,并不是缓存数据的copy,因此,对数据的修改是直接影响到缓存的,例:

  • // code by xujiwei
  • // from www.xujiwei.cn
  • // 构建一个myname对象,具有属性Name,值为”my name is xujiwei”
  • var myname={Name:”my name is xujiwei”};
  • xbsCache.put(“name”,myname);
  • // 从缓存中获取name,Name属性值为”my name is xujiwei”
  • var myname2=xbsCache.get(“name”);
  • // 给myname2赋值”xujiwei”
  • myname2.Name=”xujiwei”;
  • // 从缓存中获取name,Name属性值变为”xujiwei”
  • var myname3=xbsCache.get(“name”);

由于数据类型不同而引起的这两种情况,在使用缓存时需要分别对待,如果需要会对缓存中object类型数据进行修改,应该设置一个标志变量,以免对数据重复进行修改,从而破坏了数据的准确性。

[ASP] 在JScript中使用缓存技术

在编写ASP程序时,通常为了提高ASP程序的运行效率及减少对数据库的连接和查询,会使用缓存技术来缓存一些需要从数据库读取的数据。而在ASP中实现缓存的方法常用的就是使用Application对象。在编写ASP程序时,我们有两种语言可以选择,分别是VBScript和JScript。

在使用VBScript时,我们可以用Application缓存数组来实现缓存,例:

  • Dim rs,arr
  • rs.Open conn,sql,1,1
  • arr=rs.GetRows()
  • Application.Lock()
  • Application(“cache”)=arr
  • Applicatoin.UnLock()

在VBScript里,数组是可以存到Application对象里的,但是如果ASP的语言选择为JScript的话,那么就有些不妙了,我们在使用Application储存一个数组时,会出现以下错误:

Application object, ASP 0197 (0x80004005)

Disallowed object use

Cannot add object with apartment model behavior to the application intrinsic object.

在微软的知识库可以找到具体原因如下:

JScript arrays are considered to be “Apartment” COM components. Only Component Object Model (COM) components that aggregate the Free Threaded Marshaler (FTM) can be assigned to Application scope within an Internet Information Server (IIS) 5.0 ASP page. Because an “Apartment” component cannot aggregate the FTM (it cannot allow a direct pointer to be passed to its clients, unlike a “Both with FTM” object), JScript arrays do not aggregate the FTM. Therefore, JScript arrays cannot be assigned to Application scope from an ASP page.

以上描述引用自:PRB: Error When You Store a JScript Array in Application Scope in IIS 5.0

因此,为了解决这个问题,在Google里找了一大会,终于找到了一篇文章《Application对象的Contents和StaticObjects做Cache的一些结论》,解决了这个问题,方法就是使用Application.StaticObject存放一个Scripting.Dictionary对象,然后再使用Scripting.Dictionary对象来存放需要缓存的数据。

据此,写了一个操作缓存的类,实现put、get、remove和clear方法,使用之前,需要在global.asa中添加一个object:

  • <object id=”xbsCache” runat=”server” scope=”Application” progid=”Scripting.Dictionary”></object>

类的实现如下:

  • <script language=”JScript” runat=”server”>
  • /**
  • Title: cache operate class
  • Description: operate system cache
  • @Copyright: Copyright (c) 2007
  • @Author: xujiwei
  • @Website: http://www.xujiwei.cn/
  • @Version: 1.0
  • @Time: 2007-06-29 12:03:45
  • **/
  • var xbsCache = {
  • get: function(key) {
  • return Application.StaticObjects(“xbsCache”).Item(“Cache.”+key);
  • },
  • put: function(key, data) {
  • Application.Lock();
  • Application.StaticObjects(“xbsCache”).Item(“Cache.”+key)=data;
  • Application.UnLock();
  • },
  • remove: function(key) {
  • Application.Lock();
  • Application.StaticObjects(“xbsCache”).Remove(“Cache.”+key);
  • Application.UnLock();
  • },
  • clear: function() {
  • Application.Lock();
  • Application.StaticObjects(“xbsCache”).RemoveAll();
  • Application.UnLock();
  • }
  • }
  • </script>

如此,就完成了ASP中使用JScript时的缓存实现。

[ASP] 在JScript中使用RecordSet对象的GetRows方法

写ASP程序时,一般情况总是使用的VBScript,不过也不只是这一种选择,也可以用JScript。但在用JScript作为ASP的语言时,比用VBScript有一些小小的不方便,比如RecordSet的GetRows方法。

在ASP中操作数据库,一般都要用到RecordSet对象,如果注重程序效率的话,可能就会用到RecordSet对象的GetRows方法,把记录集对象转换成数组,而操作数组在速度上将比用RecordSet对象的MoveNext方法快很多,而且可以在取出数组后尽早释放RecordSet对象,从而减少资源的占用,这也是优化ASP性能的一个方法。

在VBScript里,用RecordSet.GetRows方法取到的是一个二维数组,里面的数据可以通过遍历数组的方式来取得。

假设现在有一个数据库,其中有一个表名为mytable,有3个字段,名称分别为id,first,second。

  • ‘ code by xujiwei
  • ‘ http://www.xujiwei.cn/
  • ‘ 定义变量
  • Dim conn,rs,data,recN,i
  • ‘ 连接数据库
  • Set conn=Server.CreateObject(“ADODB.Connection”)
  • conn.Open “Provider=Microsoft.Jet.OLEDB.4.0;Data Source=” &_
  • Server.MapPath(“data.mdb”)
  • ‘ 获取记录集
  • Set rs=conn.Execute(“SELECT id,first,second FROM mytable”)
  • ‘ 获取数据数组
  • data=rs.GetRows()
  • ‘ 关闭记录集,释放对象
  • rs.Close()
  • Set rs=Nothing
  • ‘ 获取记录数
  • recN=UBound(data,2)
  • ‘ 循环输出数据
  • For i=0 To recN
  • ‘ 注意,数组下标从0开始
  • ‘ 显示数据库中数据
  • Response.Write(“ID: “&data(0,i)&”, First: “&data(1,i)&_
  • “, Second: “&data(2,i)&”<br />”)
  • Next
  • ‘ 关闭数据库连接,释放对象
  • conn.Close()
  • Set conn=Nothing
  • %>

但是在JScript使用时,就会有一个问题,那就是JScript并没有二维数组,如果要用GetRows所获取的数据,必要将这个VBScript中的二维数组转换成JScript能识别的数组,即元素为数组的一个一维数组。

在JScript里,用GetRows方法获取的数组有一个toArray方法,可以转换成JScript中能用的数组,但是这个数组是一维的,也就是说,如果要像在VBScript一样使用的话,还需要我们自己来做转换。

查阅了MSDN及在网上搜索了相关的文章之后,我写了一个数组转换的函数用于在JScript中使用GetRows方法。

  • <script language=”JScript” runat=”server”>
  • // code by xujiwei
  • // http://www.xujiwei.cn/
  • // 定义变量
  • var conn,rs,vdata,data,recN,i;
  • // 连接数据库
  • conn=Server.CreateObject(“ADODB.Connection”);
  • conn.Open(“Provider=Microsoft.Jet.OLEDB.4.0;Data Source=”+
  • Server.MapPath(“data.mdb”));
  • // 获取记录集
  • rs=conn.Execute(“SELECT id,first,second FROM test”);
  • // 获取数据数组,并转换成为JScript中可用的数组类型
  • vdata=rs.GetRows().toArray();
  • // 获取数据表的字段数
  • i=rs.Fields.Count;
  • // 关闭记录集,释放对象
  • rs.Close();
  • rs=null;
  • // 转换数组
  • data=transArray(vdata,i);
  • // 获取记录数
  • recN=data.length;
  • // 循环输出数据
  • for(i=0;i<recN;i++) {
  • // 注意,数组下标从0开始
  • // 显示数据库中数据
  • Response.Write(“ID: “+data[i][0]+”, First: “+data[i][1]+
  • “, Second: “+data[i][2]+”<br />”);
  • }
  • // 关闭数据库连接,释放对象
  • conn.Close();
  • conn=null;
  • // 数组转换函数
  • // by xujiwei
  • // 参数:arr – GetRows方法得到的对象用toArray方法得到的数组
  • //       fieldslen – 数据表字段数
  • function transArray(arr,fieldslen) {
  • var len=arr.length/fieldslen,data=[],sp;
  • for(var i=0;i<len;i++) {
  • data[i]=new Array();
  • sp=i*fieldslen;
  • for(var j=0;j<fieldslen;j++)
  • data[i][j]=arr[sp+j];
  • }
  • return data;
  • }
  • </script>

对于一些更新频率不高,而使用次数比较多的数据,可以在成功获取数据数组之后,用Application对象来缓存起来,从而减少对数据库的查询次数,一定程序程度上优化ASP的性能。