Как обновить кэш отдельных запросов в ColdFusion 2016

Я нашел фрагмент кода, который работает под движком 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, которая обновляет этот запрос следующим образом:

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

Опять же, это работало раньше в ColdFusion 10, но теперь не работает в ColdFusion 2016. Что мне нужно сделать по-другому, чтобы обновить кеш этого конкретного запроса?


person user1100412    schedule 27.06.2017    source источник
comment
Я не работаю с версией 2016, но отсутствие типа аргумента может иметь значение. Кстати, что означает does not work?   -  person Dan Bracuk    schedule 27.06.2017
comment
Я имею в виду, что когда я обновляю переменную cachedwithin timepan, она должна обновлять кешированный запрос, чтобы обновить его новыми значениями, которые я добавил в БД. Не работает означает, что когда я выполняю обновление с помощью метода CFC, передавая аргумент 0 для временного интервала, кэшированный запрос не обновляется. Он по-прежнему отображает старые значения, а не новые, и это работало раньше в CF10.   -  person user1100412    schedule 27.06.2017
comment
@ user1100412 Я рад, что вы нашли решение. Вместо того, чтобы включать решение в свой вопрос, добавьте его как новый ответ на этот вопрос и примите его. Это нормально, чтобы ответить на свой вопрос здесь. Просто отдайте должное, как вы это сделали. Ваше здоровье.   -  person Miguel-F    schedule 17.07.2017


Ответы (3)


Да, это изменилось после 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>
person Alex    schedule 27.06.2017

Большое спасибо @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>
person user1100412    schedule 18.07.2017

Я не знаю, правильно ли то, что говорит @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>

Условие всегда должно быть истинным, чтобы запрос возвращал один и тот же набор результатов.

* Я не проверял это.

person Miguel-F    schedule 28.06.2017
comment
Я сообщил об аналогичной проблеме команде CF через Slack, которая даже более серьезна, чем ошибка cachedWithin. Команда CF проводит дальнейшую оценку, чтобы определить, как это исправить. Моя проблема заключалась в том, что последующие запросы фактически не возвращали и не обновляли переменную запроса из кеша. gist.github.com/JamoCA/fe7ff5be43560ba6f8b6c513fdf9f723 (я не могу обновиться с CF9/10 до это исправлено.) - person James Moberg; 03.07.2017