Как обновить кэш отдельных запросов в ColdFusion 2016
Автор вопроса: user1100412Ответов: 3
Я нашел фрагмент кода, который работает под движком ColdFusion 10, но не под движком ColdFusion 2016 (CF12).
У меня есть CFC, в котором хранятся кэшированные запросы, которые перехватываются вызовами функций. Скажем, у меня есть запрос, который я хочу кэшировать, но я вношу изменения в таблицу базы данных, которую использует этот запрос. Я не вижу данных в возвращенном кэшированном запросе, поэтому мне нужно обновить кеш запроса, достаточно просто. Вот как я настроил свой код:
<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, которая обновляет этот запрос следующим образом:
Опять же, это работало раньше в ColdFusion 10, но теперь не работает в ColdFusion 2016. Что мне нужно сделать по-другому, чтобы обновить кеш этого конкретного запроса?
Я не работаю с версией 2016, но отсутствие типа аргумента может иметь значение. Кстати, что означает does not work? Dan Bracuk 27.06.2017
Я имею в виду, что когда я обновляю переменную cachedwithin timepan, она должна обновлять кешированный запрос, чтобы обновить его новыми значениями, которые я добавил в БД. Не работает означает, что когда я выполняю обновление с помощью метода CFC, передавая аргумент 0 для временного интервала, кэшированный запрос не обновляется. Он по-прежнему отображает старые значения, а не новые, и это работало раньше в CF10. user1100412 27.06.2017
@ user1100412 Я рад, что вы нашли решение. Вместо того, чтобы включать решение в свой вопрос, добавьте его как новый ответ на этот вопрос и примите его. Это нормально, чтобы ответить на свой вопрос здесь. Просто отдайте должное, как вы это сделали. Ваше здоровье. Miguel-F 17.07.2017
Да, это изменилось после CF10. Это считается ошибкой, но до сих пор не исправлено. После того, как результат запроса кэшируется с использованием 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 |----- | азбука
Давайте изменим данные.
UPDATE `example` SET `foo` = 'DEF';
И как и ожидалось...
<!--- invalidate cache and fetch new data --->
<cfquery cachedWithin="#createTimeSpan(0, 0, 0, 0)#">
SELECT `foo` FROM `example`;
</cfquery>
| foo |----- | ДЭФ
А теперь давайте кэшируем самые свежие данные.
<!--- cache new data for 10 minutes --->
<cfquery cachedWithin="#createTimeSpan(0, 0, 10, 0)#">
SELECT `foo` FROM `example`;
</cfquery>
Результат в CF10
| foo |----- | ДЭФ
cachedWithin <= 0 сделал кэшированный запрос недействительным. Таким образом, следующая cachedWithin > 0 сохранила новые данные в кеше.
Результат в CF2016
| foo |----- | азбука
cachedWithin <= 0 просто пропустил кеш. Следующий cachedWithin > 0 извлекается из кеша. И кеш не изменился.
ОБНОВИТЬ
Текущий обходной путь для этой ошибки - использовать атрибут cacheID для <cfquery>, а затем сделать его недействительным с помощью cacheRemove(theCacheID).
Старый ответ
Вы можете аннулировать кеш запросов с помощью <cfobjectcache action="CLEAR">, но он аннулирует ВСЕ кешированные запросы, что довольно плохо. Другой вариант - кэшировать запрос самостоятельно, используя cachePut и получить его с помощью 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>
Ответ 2 · рейтинг 1 · user1100412
Большое спасибо @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>
Ответ 3 · Miguel-F
Я не знаю, правильно ли то, что говорит @Alex, но у меня нет причин сомневаться в нем. Я не использую ColdFusion 2016. Возможно, это еще один вариант обновления кеша для определенного запроса...
Помните, что при использовании атрибута cachedWithin тега cfquery запрос будет кэшироваться только в том случае, если выполняются все следующие условия. "Вступает в силу, только если кэширование запросов включено в Администраторе. Чтобы использовать кэшированные данные, текущий запрос должен использовать тот же оператор SQL, источник данных, имя запроса, имя пользователя и пароль." (документация по cfquery)
Сосредоточимся на этой части - та же инструкция SQL. Если вы немного измените оператор SQL, кэш будет обновлен. Поэтому, возможно, вы можете просто добавить еще одно условие в свой оператор SQL, которое вы можете использовать для обновления запроса. Возможно, вы даже сможете использовать ту же самую переменную, которая у вас уже есть time_span.
Я думаю примерно так (синтаксис может отличаться в зависимости от вашей СУБД):
<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>
Условие всегда должно быть истинным, чтобы запрос возвращал один и тот же набор результатов.