如何在ColdFusion中正确实现共享缓存?

时间:2008-10-01 06:49:56

标签: caching coldfusion scope locking

我已经构建了一个CFC,旨在作为一个动态的老化缓存,用于几乎所有值得缓存的东西。 LDAP查询,函数结果,数组,对象,您可以命名它。无论需要多少时间或资源来计算,都需要不止一次。我希望能够做一些事情:

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

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

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

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

2 个答案:

答案 0 :(得分:2)

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

回答有关锁定的问题:

命名锁应该没问题,因为它们不必总是具有相同的名称。您可以根据要访问的缓存动态命名它们。当你需要访问私有结构的一个元素时,你可以做一些像命名锁一样使用密钥作为名称。

这样,只有当某个东西试图通过名称访问同一个缓存时,锁定才会生效。

答案 1 :(得分:1)

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

<强> cache.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),这样,如果您决定将缓存移动到另一个范围,则不必使用缓存CFC将“会话”传递到init,而不是编辑300页,而是可以编辑1 CFC或您的ColdSpring配置。

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