我发现一段代码在ColdFusion 10引擎下工作,但不在ColdFusion 2016(CF12)引擎下。
我有一个CFC,其中包含被函数调用抓取的缓存查询。假设我有一个我想要缓存的查询,但是我对此查询使用的db表进行了更改。我没有看到返回的缓存查询中的数据,所以我需要刷新查询缓存,这很简单。这就是我设置代码的方式:
<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上不起作用。我需要做些什么来刷新这个特定查询的缓存?
答案 0 :(得分:4)
是的,这在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>
| FOO
| -----
| ABC
让我们改变数据。
UPDATE `example` SET `foo` = 'DEF';
正如所料......
<!--- invalidate cache and fetch new data --->
<cfquery cachedWithin="#createTimeSpan(0, 0, 0, 0)#">
SELECT `foo` FROM `example`;
</cfquery>
| FOO
| -----
| DEF
现在让我们缓存最新的数据。
<!--- cache new data for 10 minutes --->
<cfquery cachedWithin="#createTimeSpan(0, 0, 10, 0)#">
SELECT `foo` FROM `example`;
</cfquery>
| FOO
| -----
| DEF
cachedWithin <= 0
使缓存的查询失效。因此,下一个cachedWithin > 0
将新数据存储在缓存中。
| FOO
| -----
| ABC
cachedWithin <= 0
只是跳过了缓存。从缓存中提取下一个cachedWithin > 0
。缓存没有变化。
此错误的当前解决方法是使用cacheID
的{{1}}属性,然后使用<cfquery>
使其无效。
您可以使用cacheRemove(theCacheID)
无效查询缓存,但会使所有缓存查询无效,这非常糟糕。另一个选项是使用cachePut
自行缓存查询并使用cacheGet
获取查询。
这是一个提示如何做到这一点。您可能需要在此处加入<cfobjectcache action="CLEAR">
逻辑,我不确定它的目标是什么:
this.cacheSpan
答案 1 :(得分:1)
非常感谢@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>
答案 2 :(得分:0)
我不知道@Alex说的是否正确,但我没有理由怀疑他。我没有运行ColdFusion 2016.也许这是刷新特定查询缓存的另一个选项......
请记住,在使用cachedWithin
标记的cfquery
属性时,只有在满足以下所有条件时才会缓存查询。 “仅在管理员中启用查询缓存时才会生效。要使用缓存数据,当前查询必须使用相同的SQL语句,数据源,查询名称,用户名和密码。”({ {3}})
专注于这部分 - 相同的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>
条件应始终为true,因此查询将返回相同的结果集。
*我没有测试过这个。