1

我已经构建了一个 CFC,旨在用作一个动态的、老化的缓存,用于几乎所有值得缓存的东西。LDAP 查询、函数结果、数组、对象,应有尽有。任何需要时间或资源来计算并且需要不止一次的东西。我希望能够做一些事情:

  • 在应用程序之间共享 CFC
  • 定义缓存的范围(仅限服务器/应用程序/会话/当前请求)
  • 在同一个请求中同时使用不同的缓存实例
  • 使用缓存组件独立于 CFC
  • 一般遵守常识(解耦、封装、正交性、锁定)

我当然会为每个不同的任务使用不同的缓存实例,但我希望能够跨应用程序使用相同的 CFC。缓存本身(还有什么)是缓存实例私有的结构。当范围本身可能发生变化时,我将如何正确实现缓存和锁定?

对于锁定,我目前使用命名锁('CacheRead', 'CacheWrite'),这是安全的,但让我觉得很奇怪。为什么我想要一个服务器范围的锁,比如说,一个仅限会话的操作?(是的,也许这学术性的,但无论如何。)

当我想要应用程序级缓存时,将 APPLICATION 范围作为参考传递似乎也是错误的做法。有没有更好的办法?

4

2 回答 2

2

好的 - 因为我最初误解了你的问题,所以我删除了我之前的答案,以免造成任何进一步的混乱。

要回答有关锁定的问题:

命名锁应该没问题,因为它们不必总是具有相同的名称。您可以根据正在访问的缓存动态命名它们。当您需要访问私有结构的元素时,您可以执行一些操作,例如让命名锁使用密钥作为其名称。

这样,锁唯一会产生影响的情况是,如果某物试图按名称访问相同的缓存。

于 2008-10-02T11:14:20.433 回答
1

我理解您希望避免传入要缓存到的实际范围结构,但您的选择是有限的。首先想到的是传递您希望存储缓存的范围的名称(字符串)并进行评估。就其性质而言,评估效率低下,应该避免。也就是说,我很好奇它是如何实现的。我没有你的代码,所以我在这里做了一个非常简单的“存储”抽象 CFC(跳过缓存,因为它与我想要测试的内容无关):

缓存.cfc:

<cfcomponent>
    <cfset variables.cacheScope = "session" /><!--- default to session --->
    <cfset variables.cache = ""/>

    <cfscript>
    function init(scope){
        variables.cacheScope = arguments.scope;
        return this;
    }

    function cacheWrite(key, value){
        structInsert(evaluate(variables.cacheScope),arguments.key,arguments.value,true);
        return this;
    }

    function cacheRead(key){
        if (not structKeyExists(evaluate(variables.cacheScope), arguments.key)){
            return "";
        }else{
            variables.cache = evaluate(variables.cacheScope);
            return variables.cache[arguments.key];
        }
    }   
    </cfscript>
</cfcomponent>

并对其进行测试:

<!--- clear out any existing session vars --->
<cfset structClear(session)/>
<!--- show empty session struct --->
<cfdump var="#session#" label="session vars">
<!--- create storage object --->
<cfset cacher = createObject("component", "cache").init("session")/>
<!--- store a value --->
<cfset cacher.cacheWrite("foo", "bar")/>
<!--- read stored value --->
<cfset rtn = cacher.cacheRead("foo")/>
<!--- show values --->
<cfdump var="#rtn#">
<cfdump var="#session#" label="session vars">

题外话:我喜欢编写我的 setter 函数来返回“this”[如上所示],这样我就可以像 jQuery 一样链接方法调用。部分视图可以很容易地写成:

<cfset rtn = createObject("component", "cache")
    .init("session")
    .cacheWrite("foo", "bar")
    .cacheRead("foo")/>

有趣的是,这是可能的,但由于 Evaluate 的间接成本,我可能不会在生产中使用它。我想说这是传递您要缓存到的范围的足够充分的理由。

如果您仍然对此感到困扰(也许是对的?),您可以创建另一个 CFC,从所需范围抽象读取和写入,并将其传递到您的缓存 CFC 作为存储位置(非常适合ColdSpring的任务) ,这样,如果您决定将缓存移动到另一个范围,则不必编辑 300 个页面,全部使用将“会话”传递给 init 的缓存 CFC,而是可以编辑 1 个 CFC 或您的 ColdSpring 配置。

但是,当您具有请求范围时,我不完全确定为什么要进行单请求缓存。如果您正在寻找一种为当前请求缓存某些内容并在不久之后将其终止的方法,那么请求范围可能就是您想要的。当跨越多个请求时,缓存通常更有价值。

于 2008-10-27T17:19:09.650 回答