如何在 ColdFusion 2016 中刷新单个查询缓存

How to refresh individual query cache in ColdFusion 2016

我发现一段代码在 ColdFusion 10 引擎下运行,但在 ColdFusion 2016 (CF12) 引擎下不运行。

我有一个 CFC,其中包含由函数调用获取的缓存查询。假设我有一个要缓存的查询,但我对该查询使用的数据库 table 进行了更改。我没有在返回的缓存查询中看到数据,所以我需要刷新查询缓存,很简单。这就是我设置代码的方式:

<cffunction name="getVariables" access="public" returntype="query">
    <cfargument name="time_span" required="true" default="#this.cacheSpan#" />
    <cfset var qryGetVariables="">

    <!--- IF REFRESH, NEW QRYTIMESPAN --->
    <cfif arguments.time_span eq 0 AND NOT this.bln_refresh>
        <!--- IF time_span 0 but not refresh, reset to original cache span --->
        <cfset arguments.time_span = this.cacheSpan />
    </cfif>
    <cfquery name="qryGetVariables" datasource="#this.dsn#" cachedwithin="#arguments.time_span#">
        select *
          from get_variables
         order by id, value
    </cfquery>
    <cfreturn qryGetVariables>
</cffunction>

我在同一个 CFC 中调用一个函数,以下列方式刷新此查询:

this.bln_refresh = true;
<cfinvoke method="getVariables" returnvariable="qryReturn">
   <cfinvokeargument name="time_span" value="0" />
</cfinvoke>
this.bln_refresh = false;

同样,这之前在 ColdFusion 10 上有效,但现在在 ColdFusion 2016 上无效。我需要做些什么来刷新这个特定查询的缓存?

是的,这在 CF10 之后发生了变化。 It's considered as bug, but it still not fixed. 一旦使用 cachedWithin 缓存查询结果,就不能使用 createTimeSpan(0, 0, 0, 0)(等于 0)或任何负值使其无效。

演示

<!--- cache data for 10 minutes --->
<cfquery cachedWithin="#createTimeSpan(0, 0, 10, 0)#">
    SELECT `foo` FROM `example`;
</cfquery>

|富
|-----
|美国广播公司

让我们更改数据。

UPDATE `example` SET `foo` = 'DEF';

正如预期的那样...

<!--- invalidate cache and fetch new data --->
<cfquery cachedWithin="#createTimeSpan(0, 0, 0, 0)#">
    SELECT `foo` FROM `example`;
</cfquery>

|富
|-----
|防御

现在让我们缓存最新的数据。

<!--- cache new data for 10 minutes --->
<cfquery cachedWithin="#createTimeSpan(0, 0, 10, 0)#">
    SELECT `foo` FROM `example`;
</cfquery>

CF10 成绩

|富
|-----
|防御

cachedWithin <= 0 使缓存的查询无效。因此下一个 cachedWithin > 0 将新数据存储在缓存中。

CF2016成绩

|富
|-----
|美国广播公司

cachedWithin <= 0 只是跳过了缓存。接下来的 cachedWithin > 0 从缓存中获取。并且缓存没有改变。


更新

此错误的当前解决方法是使用 <cfquery>cacheID 属性,然后使用 cacheRemove(theCacheID).

使其无效

旧答案

您可以使用 <cfobjectcache action="CLEAR"> 使查询缓存无效,但是 它会使所有缓存的查询无效,这非常糟糕。另一种选择是使用 cachePut and fetching it using cacheGet.

自己缓存查询

这里有一个提示,说明如何操作。您可能必须在此处合并您的 this.cacheSpan 逻辑,我不太确定它的目标是什么:

<cffunction name="getVariables" access="public" returntype="query">

    <cfargument name="time_span" required="true" default="#this.cacheSpan#">

    <cfset var qryGetVariables = "">

    <cfset var cacheKey = "qryGetVariables"> <!--- make sure the key is unique and only used in this function --->
    <cfset var useCache = ((arguments.time_span lte 0) or this.bln_refresh)>

    <cfif useCache>
        <cfset qryGetVariables = cacheGet(cacheKey)>
    </cfif>

    <cfif not isQuery(qryGetVariables)>

        <cfquery name="qryGetVariables" datasource="#this.dsn#">
            select *
              from get_variables
             order by id, value
        </cfquery>

        <cfset cachePut(cacheKey, qryGetVariables, arguments.time_span)>

    </cfif>

    <cfreturn qryGetVariables>
</cffunction>

我不知道@Alex说的对不对,但我没有理由怀疑他。我不是 运行 ColdFusion 2016。也许这是为特定查询刷新缓存的另一种选择...

请记住,当使用 cfquery 标记的 cachedWithin 属性时,它只会在满足以下所有条件时才缓存查询。 "只有在 Administrator 中启用查询缓存时才会生效。要使用缓存数据,当前查询必须使用相同的 SQL 语句、数据源、查询名称、用户名和密码。" (cfquery documentation)

关注这部分 - 相同的 SQL 语句。如果稍微更改 SQL 语句,缓存将被刷新。因此,也许您可​​以向 SQL 语句添加另一个条件,您可以使用它来刷新查询。您甚至可以使用您已经拥有的相同变量 time_span.

我在想这样的事情(语法可能因您的 DBMS 而异):

<cfquery name="qryGetVariables" datasource="#this.dsn#" cachedwithin="#arguments.time_span#">
    select *
    from get_variables
    where '#arguments.time_span#' = '#arguments.time_span#'
    order by id, value
</cfquery>

条件应始终为真,因此查询将 return 相同的结果集。

*我没有测试过这个。

非常感谢 @Alex,我发现了以下似乎适用于我们服务器的解决方案:

<cffunction name="getVariables" access="public" returntype="query">
    <cfargument name="time_span" required="true" default="#this.cacheSpan#" />
    <cfset var qryGetVariables="" />
    <cfset var flt_qryTimeSpan=0>

    <cfif NOT cacheIdExists("qryGetVariablesCache") OR this.bln_refresh>
        <cfquery name="qryGetVariables" datasource="#this.dsn#" cachedwithin="#flt_qryTimeSpan#">
            select *
              from get_variables
             order by id, value
        </cfquery>
        <cfset cacheRemove("qryGetVariablesCache") />
        <cfset cachePut("qryGetVariablesCache",qryGetVariables,this.cacheSpan) />
    <cfelse>
        <cfset qryGetVariables = cacheGet("qryGetVariablesCache") />
    </cfif>
    <cfreturn qryGetVariables>

</cffunction>