12.01.2007, 14:58 | #1 |
MCTS
|
Цикл, ttsabort и continue
Всем привет!
Столкнулся с такой проблемой (может она обсуждалась уже, но я что то не нашел). Выбираю в цикле while select записи таблицы ProjTable. Там же в цикле после проверки некоторого условия откатываю транзакцию и хочу перейти на следующую строку ProjTable в цикле. Но после вызова continue следующая строка не выбирается. То есть цикл как и положено проходит снова, но курсор ProjTable указывает на ту же самую запись, что и при первом проходе. Для наглядности написал джоб который описывает данную ситуацию. Причем если цикл дополнить условием по projId (while select projT where projT.projId == "ИД_Проекта"), то continue работает нормально. X++: static void Test_TTS_Continue(Args _args) { ProjTable projT; int i = 0; ; ttsbegin; while select projT // while select projT where projT.projId == "ИД_Проекта" { info(int2str(i) + ', projId = ' + projT.ProjId); i++; if (i>100) return; ttsabort; ttsbegin; continue; } ttscommit; } Заранее благодарен. Последний раз редактировалось PavelX; 12.01.2007 в 15:01. |
|
12.01.2007, 15:52 | #2 |
MCTS
|
Цитата:
Там же в цикле после проверки некоторого условия откатываю транзакцию
не X++: if (i>100)
__________________
В глухомани, в лесу Несмотря на красу Дни проводит Лиса Патрикевна. Я никак не пойму Отчего, почему Не пускают куму На деревню |
|
12.01.2007, 15:56 | #3 |
NavAx
|
Вообще в x++ не рекомендуется использование ttsabort и открытие/закрытие одной транзакции на разных уровнях вложенности.
|
|
12.01.2007, 16:47 | #4 |
----------------
|
Давайте подумаем вместе.
- Открыли транзакцию - Открыли курсор - Получили результат в несколько строк (fetch) - Закрыли транзакцию - Открыли транзакцию - Захотели получить еще данные из курсора (fetch) Что должен ответить SQL-сервер? |
|
12.01.2007, 23:30 | #5 |
Участник
|
Скорее всего, требовался уровень изоляции READ_COMMITED - он в Аксапте устанавливается только под транзакциями . А закрывают и открывают опять - чтобы меньше сталкиваться на блокировках.
Вообще, нехорошо так делать, если в цикле очень много проходов, с точки зрения СУБД. |
|
13.01.2007, 12:28 | #6 |
Участник
|
Здесь получается такая схема работы.
1. Открыли транзакцию 2. Открыли курсор 3. Получили результат в несколько строк (fetch) 4. Закрыли транзакцию 5. Закрыли курсор 6. Открывается и закрывается транзакция несколько раз. Пока в буфере на клиенте есть записи - запросы на получение данных не идут. 7. Как только на клиенте закончились записи в буфере - переходим к пункту 2 При такой схеме легко попасть в бесконечный цикл, если нет дополнительных условий для его прерывания Очень многое зависит от количества записей, получаемом при выборке (фетче) (при этом надо учесть, что это не константа и может отличаться для первой и последующих, а так же зависит от опций в select'е, например, firstfast). Если количество записей в результате выборки меньше размера буфера (в данном случае, упрощая, это кол-во строк в нем помещающихся), то цикл отработает (в исходном вопросе при наложении условия в where так и происходит). Если количество записей больше или равно размеру буфера, то попадаем в бесконечный цикл, в котором с какой-то периодичность записи будут повторяться В общем, так делать - себе дороже. 2 PavelX Расписали бы вы полнее задачу. Но первое подложение сделаю - используйте UserConnection для вашей выборки (или для операций по изменению данных) X++: static void Test_TTS_Continue(Args _args) { ProjTable projT; int i = 0; UserConnection conn = new UserConnection(); ; projT.setConnection(conn); ttsbegin; while select projT // while select projT where projT.projId == "ИД_Проекта" { info(int2str(i) + ', projId = ' + projT.ProjId); i++; if (i>100) return; ttsabort; ttsbegin; continue; } ttscommit; }
__________________
Axapta v.3.0 sp5 kr2 |
|
|
За это сообщение автора поблагодарили: kashperuk (2), PavelX (1). |
13.01.2007, 12:35 | #7 |
MCTS
|
2 Russland:
Не, условие конечно не это. Этот джоб я вообще написал чтоб показать в чем проблема. Просто когда я его запускаю у себя, цикл зацикливается притом, что значение projT остается одним и тем же. Вот я и хотел узнать у меня только так или это у всех. 2 Wamr: Да, видимо для SQL-сервера такая конструкция равносильна новому запросу. Просто как то это неочевидно еще пока для меня, мало опыта в аксапте... В понедельник попробую вынести while select за транзакцию, о результатах сообщу. |
|
13.01.2007, 13:13 | #8 |
MCTS
|
Ситуация следующая:
Есть модуль расчета процентов и комиссионных по займам. Проекты это займы. Каждый проект верхнего уровня (родительский) - это займы у конкретного заимодателя, все его подпроекты - это займы определенных клиентов у этого заимодателя. Данный цикл используется в классе разноски платежей по займам по заимодателям. То есть этот цикл выполняется по родительским проектам (while select ProjT where ProjT.ParentId == ""), и за каждый проход разносит платежи по одному заимодателю. Всего таких проходов не много, порядка 10-15. Параллельно разноске в этом же цикле вызываются классы рассчета суммы комиссий и удержаний. Так вот при условии, что если сумма всех платежей по данному заимодателю будет меньше суммы комиссии, то такие платежи нужно отложить. Все дело в том что с налету вычленить расчет суммы комиссий и платежей из кучи классов разноски представилось проблематичным, я решил просто выполнять проверку этого условия в конце цикла и если она не проходила то отменять транзакцию. Понятно что это далеко не лучший вариант... 2 AndyD: Спасибо за наводку, в понедельник попробую ЗЫ. Прошу прощения если спутанно объяснил. Последний раз редактировалось PavelX; 13.01.2007 в 13:19. |
|
15.01.2007, 07:11 | #9 |
MCTS
|
Всем огромное спасибо за помощь, в особенности AndyD. С UserConnection все заработало .
Последний вопрос, при использовании UserConnection много подводных камней можно ожидать? и каких? |
|