【问题标题】:How to properly implement a shared cache in ColdFusion?如何在 ColdFusion 中正确实现共享缓存?
【发布时间】:2010-09-14 11:08:37
【问题描述】:

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

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

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

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

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

【问题讨论】:

    标签: caching coldfusion scope locking


    【解决方案1】:

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

    回答您关于锁定的问题:

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

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

    【讨论】:

    • 感谢您的努力! :-) 我想我会采用这种方法并在创建组件时生成 UUID 作为锁名称。这样,整个锁定的东西就变得更加自给自足了。
    • 很高兴为您提供帮助。祝你好运,快乐缓存!
    【解决方案2】:

    我理解您希望避免传入您想要缓存到的实际作用域结构,但您的选择是有限的。首先想到的是传递您希望存储缓存的范围的名称(字符串)并进行评估。就其性质而言,评估效率低下,应该避免。也就是说,我很好奇它是如何实现的。我没有你的代码,所以我在这里做了一个非常简单的“存储”抽象 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),这样,如果您决定将缓存移动到另一个范围,则不必编辑 300 页全部使用缓存 CFC 将“会话”传递给 init,而是可以编辑 1 个 CFC 或您的 ColdSpring 配置。

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

    【讨论】:

    • 关于单请求“用例”:另一个 CFC 中的一组递归函数使用我的缓存对象进行透明的函数结果缓存。函数以正常方式调用,在它们开始工作之前,它们会检查它们最近是否为当前参数计算了结果。
    • 我认为我描述的将单独的范围抽象 cfc 注入缓存 cfc 的方法是最好的方法。
    猜你喜欢
    • 2011-05-27
    • 2010-10-01
    • 2021-02-25
    • 2018-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多