|
19.03.2009, 14:12 | #1 |
MCTS
|
Баг inventTable
На всякий случай напишу все подробно.
В методе InventTable.insert() super() обрамлен транзакцией. Есть у меня класс (от RunBaseBatch), в котором суть метода run() примерно такова: X++: try { ttsbegin; while () { this.process(container); } ttscommit; } catch { throw error(); } В одном из таких классов происходит заполнение InventTable: X++: void process(container) { // .... inventTable.insert(); if (- ) throw error(); //.... } X++: select firstonly inventTable where inventTable.ItemId == "Первое значение в имп. файле"; Что удивительно: X++: select firstonly inventTable; Первый запрос (с условием) начинает нормально работать только если перезагрузить аос. Как это исправить? |
|
19.03.2009, 14:25 | #2 |
Участник
|
Спасибо.
Добавил к теме теги "Баг", "ошибка". а в какой версии проявляется? |
|
19.03.2009, 14:27 | #3 |
Участник
|
Какие параметры кэширования у вас установлены для этой таблицы?
|
|
19.03.2009, 14:27 | #4 |
Участник
|
Может быть кеш дурит ?
Попробуйте перед выборкой сделать X++: inventTable.disableCache(true); |
|
19.03.2009, 14:42 | #5 |
MCTS
|
Цитата:
Какие параметры кэширования у вас установлены для этой таблицы?
Сравнение слоев показывает, что изменены только: ModifiedDate #Yes ModifiedTime #Yes ModifiedBy #Yes CreatedDate #Yes CreatedTime #Yes CreatedBy #Yes AX3.0 sp5 fp2 (Oracle 10g) Цитата:
Может быть кеш дурит ?
Попробуйте перед выборкой сделать |
|
19.03.2009, 15:01 | #6 |
Участник
|
Ну при чем здесь "изменены"?
По-умолчанию у этой таблицы свойство CacheLookup = found. В хелпе написано. Цитата:
All successful caching key selects are cached. All caching key selects are returned from cache if the record exists there. A select forupdate in TTS will force reading from the database and replaces the record in the cache.
This is typically used for static tables like ZipCodes where the normal case is that the record exists. не очень понимаю, почему у вас не работает disableCache. в принципе должен. либо вы его не туда поместили. либо он на самом деле не работает в Оракле. |
|
19.03.2009, 15:08 | #7 |
Участник
|
Может транзакция на момент перечитывания каким то чудом не откатилась ?
Что говорит appl.ttsLevel() ? |
|
19.03.2009, 15:10 | #8 |
MCTS
|
Цитата:
Ну при чем здесь "изменены"?
По-умолчанию у этой таблицы свойство CacheLookup = found. Цитата: Цитата:
Какие параметры кэширования у вас установлены для этой таблицы?
Сравнение слоев показывает, что изменены только: ModifiedDate #Yes ModifiedTime #Yes ... |
|
19.03.2009, 15:17 | #9 |
Участник
|
Протормозил. Извините. Подумал, что вы нашли вот такие изменения...
|
|
19.03.2009, 15:25 | #10 |
MCTS
|
Цитата:
Может транзакция на момент перечитывания каким то чудом не откатилась ?
Что говорит appl.ttsLevel() ? |
|
19.03.2009, 15:35 | #11 |
MCTS
|
В принципе до вставки записи в базу можно не проверять (так как это не работает)
X++: inventTable = null; inventTable.clear(); inventTable.initValue(); if (InventTable::exist(sCode)) throw error(strfmt("Запись существует", sCode)); Цитата:
A select forupdate in TTS will force reading from the database and replaces the record in the cache.
еще чудеса. InventTable::exist(sCode) может выдать, что сущ. не первая запись, а скажем 14-я Последний раз редактировалось Eldar9x; 19.03.2009 в 15:53. |
|
19.03.2009, 15:50 | #12 |
Участник
|
Не думаю, что это некрасиво. В стандарте достаточно мест, где запись выбирается для обновления, хотя затем никакого обновления не происходит. Насколько я понимаю, именно для того, чтобы получать актуальную версию, в не зависимости от того правильно ли отрабатывает кэш или нет.
Для примера можно посмотреть классы работы с журналами главной книги - ledgerJournalEngine - например. |
|
19.03.2009, 15:56 | #13 |
MCTS
|
ура, нашел. flush inventTable; и все путем
|
|
19.03.2009, 16:30 | #14 |
Участник
|
|
|
19.03.2009, 16:38 | #15 |
MCTS
|
Цитата:
Как вы его использовали ?
X++: inventTable = null; inventTable.clear(); inventTable.initValue(); inventTable.disableCache(true) if (InventTable::exist(sCode)) throw error(strfmt("Запись существует", sCode)); или делать запрос по курсору inventTable прямо в методе, то это тоже сработает. Завтра проверю. Цитата:
Не думаю, что это некрасиво. В стандарте достаточно мест, где запись выбирается для обновления, хотя затем никакого обновления не происходит. Насколько я понимаю, именно для того, чтобы получать актуальную версию, в не зависимости от того правильно ли отрабатывает кэш или нет.
Для примера можно посмотреть классы работы с журналами главной книги - ledgerJournalEngine - например. Последний раз редактировалось Eldar9x; 19.03.2009 в 17:04. |
|
19.03.2009, 17:05 | #16 |
Участник
|
Правильное подозрение
Проще в данном случае код из Exist() вытащить. |
|
19.01.2010, 17:16 | #17 |
NavAx
|
Наступил на те же грабли, но в AX 4.0 SP2.
Пытаюсь импортировать данные группой определений, одна из таблиц - UnitConvert (с режимом кэширования EntireTable). В результате импорта (есть доработка, которая всю сессию импорта проводит в одной транзакции), и вылетания в середине импорта ошибки по throw(), получаем, что изменения в других, "нормальных" таблицах откатились, а в UnitConvert видны записи, которые вставлялись туда импортом. Ессно, в самой базе таких записей нет, но при попытке импортировать заново - выпадает сообщение о уже существующих записях (срабатывает SysDataImportDefBase.findFromKeyData. Добавление же в него X++: common = new DictTable(_tableId).makeRecord(); flush common; Сбрасывать весь кэш AOSа при начале импорта или его неуспешном окончании из-за какого-то товарища, неправильно заполнившего импортные таблицы как-то не комильфо. Есть ли другие способы решения?
__________________
Жизнь прекрасна! Если, конечно, правильно подобрать антидепрессанты... Последний раз редактировалось Maximin; 19.01.2010 в 17:19. |
|
19.01.2010, 18:18 | #18 |
NavAx
|
Пока сделал тупо - перед импортом и после него (метод SysDataImportDefBase.importTable) очередной таблицы делает вызов серверного static метода с упомянутыми выше двумя строками, точнее Dictionary::dataFlush(_tableId). Работает.
Но как ни странно - после неудачного импорта (падает на другой таблице, в UntiConvert к тому времени всё уже залито нормально) вставленные в UnitConvert строки все равно видны, т.е. уже после вставки записей кэш все равно не очищается?! В общем, как бы то ни было, при повторных запусках записи ищутся/не ищутся правильно. Принцип идемпотентности почти соблюден.
__________________
Жизнь прекрасна! Если, конечно, правильно подобрать антидепрессанты... Последний раз редактировалось Maximin; 19.01.2010 в 18:42. Причина: Уточнил замену на Dictionary::dataFlush( |
|
19.01.2010, 22:15 | #19 |
Участник
|
Мне кажется что проблема в том что кеш не поддерживает нормально транзакции. Т.е. в нем остались грязные данные транзакции которую откатили.
Хороший повод написать запрос в MBS на исправление. Думаю что можно просто сбрасывать серверный кеш перед импортом и при перехвате ошибки. Издержки не так велики - это ведь не редактирование записи, а достаточно редкий массовый импорт. Тем более что кеш можно сбросить для конкретной таблицы (если не ошибаюсь - SysFlushData для всех сбросит - это слишком убойный вариант) в нашем случае достаточно выполнить flush common на сервере. |
|
20.01.2010, 01:38 | #20 |
Участник
|
Я думаю, что это очень сложно грамотно исправить на уровне МС.
Пришлось бы каким-то образом отслеживать на уровне ядра, какие записи вставлялись в этой транзакции, и удалять из кэша только эти записи - ведь прост очищать кэш тоже не очень кошерно |
|
|
За это сообщение автора поблагодарили: glibs (1). |