cftransaction будет запускать только первый cfquery, пропуская второй

Я пытаюсь писать в две разные таблицы, обе в одной базе данных. В одной CFTRANSACTION с двумя CFQUERY первый CFQUERY будет правильно вставлен, а второй (тоже INSERT) просто пропущен. Ошибок не возникает, я вижу данные в первой таблице, а закомментирование первого INSERT позволит второму пройти по желанию.

Упрощенная версия моего кода:

<cffunction name="insertReport">
<cfset var strReturn="">
<cftransaction>
<cftry>
<cfquery name="updateTable1" datasource="DB1">
...
</cfquery>
<cfquery name="UpdateTable2" datasource="DB1">
...
</cfquery>

<cfcatch type="any">
<cfset errMsg = "#cfcatch.Message#">
</cfcatch>
</cftry>

<cfif trim(errMsg) eq ''>
<cftransaction action="commit">
<cfelse>
<cftransaction action="rollback">
<cfset strReturn = "Error: #errMsg#.">
</cfif>
</cftransaction>

<cfreturn strReturn>
</cffunction>

Это, вероятно, что-то очень простое, но я застрял. Любая помощь приветствуется.


person MLynch    schedule 07.02.2018    source источник
comment
Я обновил свой ответ. Кажется, работает нормально после определения errMsg. Какую версию CF вы используете?   -  person luxdvie    schedule 07.02.2018
comment
ColdFusion 2016, и я подтвердил, что мы разрешили несколько транзакций для этого источника данных. Я также определил errMsg (и вторичный errMsg2 для захвата любых деталей), но все равно не повезло.   -  person MLynch    schedule 07.02.2018
comment
Как вы проверяете, что insert не произошло? Я не понимаю, как это могло бы произойти, если бы реальный код не содержал условную логику, например оператор if/else, который пропускает запрос при определенных условиях. Когда я не могу понять проблему, я начинаю устранение неполадок с ОЧЕНЬ ванильного тестового примера (без функций, try/catch, ....). Только cftransaction и два запроса. Если это сработает, начните добавлять остальную логику, пока все не сломается.   -  person SOS    schedule 07.02.2018
comment
Я использую Sybase Central и SQLANY12 - Interactive SQL для просмотра макетов таблиц и просмотра данных в них.   -  person MLynch    schedule 07.02.2018
comment
Вы, конечно, понимаете, что try/catch предотвращает появление ошибок, верно?   -  person Dan Bracuk    schedule 07.02.2018
comment
Что произойдет, когда вы попробуете ванильный тестовый пример, о котором я упоминал выше? Никаких функций или обработки ошибок.   -  person SOS    schedule 07.02.2018
comment
Мы использовали аналогичные операторы try/catch, присваивающие 'cfset errMsg = #cfcatch.Message#', во многих предыдущих кодах, и это всегда показывало нам, когда возникает ошибка. Мы ничего не получаем здесь.   -  person MLynch    schedule 07.02.2018
comment
Это может быть, но если что-то работает не так, как ожидалось, что-то должно быть по-другому. Пришло время отбросить все ожидания и начать с очень простого тестового примера. Кроме того, проверьте очевидные вещи, такие как кеширование, правильный источник данных, таблицы и т. д.   -  person SOS    schedule 07.02.2018


Ответы (2)


Обновить

Я только что попробовал приведенный ниже код на CF11, и он работал нормально. Единственная ошибка, которую я получил, заключалась в том, что errMsg не было определено, чего нет в вашем коде, пока не произойдет <cfcatch>. Я определил errMsg и повторно запустил - это было успешно.

<cffunction name="insertReport">
    <cfset var strReturn="">
    <cfset errMsg = "">
    <cftransaction>

    <cftry>
        <cfquery name="updateTable1" datasource="DS1">
            INSERT INTO ...
        </cfquery>

        <cfquery name="UpdateTable2" datasource="DS1">
            INSERT INTO ...
        </cfquery>

    <cfcatch type="any">
        <cfset errMsg = "#cfcatch.Message#">
    </cfcatch>
    </cftry>

    <cfif trim(errMsg) eq ''>
        <cftransaction action="commit">
    <cfelse>
        <cftransaction action="rollback">
        <cfset strReturn = "Error: #errMsg#.">
    </cfif>

    </cftransaction>

    <cfreturn strReturn>
</cffunction>

<cfoutput>#insertReport()#</cfoutput>

Относительно нескольких источников данных

Согласно этому форуму Adobe и это сообщение SO, вы должны зафиксировать изменения в каждом источнике данных, прежде чем переходить к следующему.

Согласно сообщению SO, это будет работать:

<cftransaction action="begin">

    <cfquery datasource="foo">
    select * from foo_test
    </cfquery>

<cftransaction action="commit"><!-- Commit before switching DSNs --->

   <cfquery datasource="bar">
    select * from bar_test
    </cfquery>

</cftransaction>

Обратите внимание, что если вы можете получить доступ к своим данным через один источник данных, используя имена из трех частей (например, fooDB.dbo.table ), вы можете писать в разные базы данных в одном <cftransaction>

person luxdvie    schedule 07.02.2018
comment
Конечно, я сделал опечатку в своем первом посте, потому что это просто моя удача сегодня. Я НЕ меняю источники данных - это одна и та же база данных, две разные таблицы. Очень жаль, но спасибо, что так быстро! - person MLynch; 07.02.2018

Спасибо всем, кто помог. Оказывается, проблема заключалась в том, что мы использовали CFQUERYPARAM в CFQUERY вместо жесткого кодирования значений, и они генерировали исключения Null Pointer.

Кажется, что эти элементы CFQUERYPARAM будут правильно записывать в базу данных, когда у нас будет только один CFQUERY, но все же выдаст это исключение нулевого указателя, которое пропустит второй CFQUERY. Поскольку нулевой указатель выдавал только значение «#cfcatch.type#», а не «#cfcatch.Message#» или «#cfcatch.detail#», которые искала наша проверка ошибок, мы не помечали проблему.

Сейчас мы рассматриваем возможность использования jTDS, чтобы посмотреть, решит ли это проблему.

person MLynch    schedule 08.02.2018
comment
(Обновление) Обычно вы должны использовать cfqueryparam, потому что он имеет много преимуществ. Что заставляет вас думать, что это проблема с драйвером? Нулевой указатель чрезвычайно распространен. Скорее всего, в данном случае это указывает на другую логическую ошибку. Прежде чем менять драйверы, я бы сначала выяснил фактическую причину. Используйте cfdump var="#cfcatch#" для отображения полного сообщения об ошибке. - person SOS; 08.02.2018
comment
Эта ветка заставила нас поверить, что нам нужен другой драйвер: forums.adobe.com/thread/692745 - person MLynch; 08.02.2018
comment
A) Мы используем драйверы com.sybase.jdbc4jdbc.SybDriver в течение последних нескольких лет без проблем. Недавно мы обновились до ColdFusion 2016 и не столкнулись с какими-либо проблемами, связанными с ним. Б) Коллега, который первоначально разработал наш сайт, предложил мне использовать jTDS, а не Adobe. Я просто исхожу из того, что он сказал использовать. C) Ваши примеры GitHub — это в значительной степени то, чем мы занимаемся. Код отлично записывает в базу данных, но выдает это, казалось бы, нефатальное исключение, которое пропускает любой дополнительный CFQUERY, который мы пытаемся запустить. - person MLynch; 08.02.2018
comment
Что ж, нет ничего плохого в использовании jTDS. Попытка исключить другие причины, которые могут иметь более простые решения. казалось бы, не фатальное исключение Ну, это является фатальным исключением, но... логика try/catch меняет это и позволяет коду продолжаться в любом случае. Что я имел в виду под C), можете ли вы потратить несколько минут, чтобы собрать тестовый пример, который запускает NP .. который мы можем протестировать независимо? - person SOS; 08.02.2018
comment
Извиняюсь, что я имел в виду под «кажущимся нефатальным» то, что он записывает все нужные данные в базу данных. Нет пустых полей, все данные, которые мы отправляем, сохраняются правильно. Кажется действительно странным, что мы получаем ошибку, которая на самом деле не показывает никаких симптомов. Вот пример кода от моего коллеги, который также работает над этим: /а> - person MLynch; 08.02.2018
comment
(Обновление) Хм... если #testNum# равно 99999999999, то этот 1-й запрос должен выдать совершенно другую ошибку, даже до того, как запрос будет запущен, потому что 99999999999 недопустимо для cf_sql_integer. Это слишком большое. Каков фактический тип данных этого столбца в БД? - person SOS; 08.02.2018
comment
Да, 99999999999 был просто примером. Это целое число всегда будет ‹ 1000. У нас есть несколько типов данных, включая целое число, десятичное число, varchar и даты. Простите мое невежество (и спасибо за всю эту помощь), но может ли несоответствие в cf_sql_[type] вызвать ошибку Null Pointer, даже если данные сохраняются правильно? - person MLynch; 08.02.2018
comment
(Редактировать) Ну, водители - странные звери, поэтому я не скажу, что это невозможно, но... у меня не было такой проблемы. Обычно это что-то еще в коде, вызывающее проблемы. Неправильный cf_sql_[type] обычно просто выдает ошибку ИЛИ БД пытается неявно преобразовать все в правильный тип. Вот почему я надеялся увидеть реальный пример того, что вызывает ошибку, и сам фактический дамп ошибки. Может быть какая-то другая причина. По крайней мере, кто-то другой, работающий с Sybase, может подтвердить или опровергнуть эту теорию. - person SOS; 08.02.2018
comment
Боюсь, мой босс параноик, что мы раздаем проприетарный код, так что я не могу столько предложить. Не очень полезно, я знаю. Но еще раз спасибо за вашу помощь, вы дали мне несколько полезных вещей для изучения. - person MLynch; 08.02.2018
comment
Совершенно понятно. Хотя для простых случаев обычно можно создать небольшой чисто вымышленный пример, демонстрирующий проблему. Используйте глупые вымышленные значения, такие как виджеты, фрукты или названия групп. Пока это представляет реальную проблему, например, использование 99999999999 для представления числа длиной 11 цифр, фактические имена столбцов и ввод не имеют большого значения. Это то, что я и многие люди здесь делают. Например, мой предыдущий пример John Smith ;-) - person SOS; 09.02.2018