AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 25.08.2010, 16:01   #1  
HorrR is offline
HorrR
Участник
 
340 / 30 (2) +++
Регистрация: 18.02.2008
Адрес: Киев
Одновременная вставка записей, совпадающих по индексу.
Билд 4.0.2503.1208, но насколько понимаю, тут вопрос вне версионный.

Для начала опишу модель архитектуры.

Есть некоторый ф-ционал(предположим, что примитивный логгер показателей системы во время некого события).

Метод для вызова логера находится внутри некого метода, для простоты будем считать, что это некоторый апдейт.
Что-то вроде:

X++:
ttsbegin;
//Инициализация только для примера. Суть в том, что до вызова логера должна
//отработать одна часть процесса
someBuffer.SomeField   = SomeNewValue;
someBuffer.SomeField2 = SomeNewValue2;
someBuffer.SomeField3 = SomeNewValue3;
//вызов логера
Loger.logit();
//Вторая часть процесса после логера + окончательный апдейт.
someBuffer.update();
ttscommit;
Loger.logit(); делает примерно следующее - пишет в таблицу лога показатели, если только таблица лога ещё не содержит записи, которая дублирует нашу по индексным полям. Для упрощения - эти поля дата логирования, период логирования и подпериод. Не спрашивайте зачем) Так нужно! В общем, эти поля формируют уникальный индекс - только одна запись за данную дату, период и подпериод логирования.

Так вот, в чем суть, если процесс, в который внедрен вызов логера запускается одновременно на двух клиентах(а такая ситуация на проекте, увы, встречается в реальной практике) - происходит следующее: вылетает ошибка о невозможности записи в таблицу логера, так как запись существует, но худшее то, что при этом прерывается процесс.

Что я только не делал:
- и запись в лог в Try-catch обрамлял, наивно думая, что в такой ситуации должна инициироваться исключительная ситуация UpdateConflict(Хотя так же перепробовал и UpdateConflictNotRecovered и просто Error и вообще кэтч блок без фильтра), но увы, catch блок ничего ловится.
- и OCC на таблице логгера отключил(эфект частичный, на 2-3 тестах отрабатывает хорошо, на 4ом все-равно валится).

В итоге, у меня появился лишь один сомнительный вариант: сделать индекс по дате, пироду и под-периоду логирования неуникальным и потом чистить повторяющиеся варианты.

В общем, если есть у кого более интересные идеи - милости прошу.
__________________
Axapta has seduced me deadly!
Старый 25.08.2010, 16:15   #2  
lev is offline
lev
Ищущий знания...
Аватар для lev
Oracle
MCBMSS
Axapta Retail User
 
1,723 / 491 (20) +++++++
Регистрация: 18.01.2005
Адрес: Москва
на вскидку.
1. сделать индекс не уникальным.
2. в методе validateWrite() таблицы написать проверку на дубликат.
3. перед инсертом записи в таблицу вызывать validateWrite() (что кстати BP настоятельно реомендует делать и перед инсертом и перед апдейтом).

т.е. в итоге в методе logit()должно появиться:
X++:
if (log.validateWrite())
    log.insert();
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с)
С Уважением,
Елизаров Артем
Старый 25.08.2010, 16:24   #3  
HorrR is offline
HorrR
Участник
 
340 / 30 (2) +++
Регистрация: 18.02.2008
Адрес: Киев
lev, ну точно так же на вскидку могу предположить, что если метод будет запущен одновременно, то и validateWrite в обоих случаях вернет true, так как дубликата на тот момент ещё не будет в базе.
__________________
Axapta has seduced me deadly!
Старый 25.08.2010, 16:28   #4  
tricky is offline
tricky
Участник
 
140 / 64 (3) ++++
Регистрация: 03.05.2005
Адрес: Гуково
Честно, не знаю есть ли в "четверке" Exception "DuplicateKeyException".
В "пятерке" именно это исключение "вываливается".
Старый 25.08.2010, 16:30   #5  
HorrR is offline
HorrR
Участник
 
340 / 30 (2) +++
Регистрация: 18.02.2008
Адрес: Киев
5ке повезло!) В 4ке нет такого вида исключений. Мало того, просто catch без фильтра тоже ничего не ловит.
__________________
Axapta has seduced me deadly!
Старый 25.08.2010, 16:35   #6  
tricky is offline
tricky
Участник
 
140 / 64 (3) ++++
Регистрация: 03.05.2005
Адрес: Гуково
Хм... в 3-ке генерится исключение "Error" ))
Старый 25.08.2010, 16:36   #7  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2476 (88) +++++++++
Регистрация: 20.08.2005
Исключение внутри блока ttsbegin/ttscommit передает управление на следующий оператор после ttscommit самого верхнего уровня.
Т.е. обработчик должен выглядеть так
X++:
try
{
    ttsbegin;
    // что-то делаем
    ttscommit;
}
catch
{
    // обрабатываем исключение
}
Если у вам несколько вложенных ttsbegin/ttscommit, то исключения надо ловить на первом уровне
__________________
Axapta v.3.0 sp5 kr2
За это сообщение автора поблагодарили: tricky (1), HorrR (1).
Старый 25.08.2010, 16:37   #8  
lev is offline
lev
Ищущий знания...
Аватар для lev
Oracle
MCBMSS
Axapta Retail User
 
1,723 / 491 (20) +++++++
Регистрация: 18.01.2005
Адрес: Москва
Цитата:
Сообщение от HorrR Посмотреть сообщение
lev, ну точно так же на вскидку могу предположить, что если метод будет запущен одновременно, то и validateWrite в обоих случаях вернет true, так как дубликата на тот момент ещё не будет в базе.
т.е. Вы хотите сказать, что параллельно выполняется один и тот же код строка в строку в двух процессах? очень слабо в это вериться...
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с)
С Уважением,
Елизаров Артем
Старый 25.08.2010, 16:43   #9  
HorrR is offline
HorrR
Участник
 
340 / 30 (2) +++
Регистрация: 18.02.2008
Адрес: Киев
Цитата:
Сообщение от lev Посмотреть сообщение
т.е. Вы хотите сказать, что параллельно выполняется один и тот же код строка в строку в двух процессах? очень слабо в это вериться...
Именно так. В определенное время на двух клиентах стартует один и тот же процесс. Не совсем пакетная отработка но практически.
__________________
Axapta has seduced me deadly!
Старый 25.08.2010, 16:46   #10  
tricky is offline
tricky
Участник
 
140 / 64 (3) ++++
Регистрация: 03.05.2005
Адрес: Гуково
Предположу также, что может вводить в заблуждение выводимый инфолог.
В этом случае можно воспользоваться этим советом: Закрыть программно Infolog
Старый 25.08.2010, 16:56   #11  
lev is offline
lev
Ищущий знания...
Аватар для lev
Oracle
MCBMSS
Axapta Retail User
 
1,723 / 491 (20) +++++++
Регистрация: 18.01.2005
Адрес: Москва
Цитата:
Сообщение от HorrR Посмотреть сообщение
Именно так. В определенное время на двух клиентах стартует один и тот же процесс. Не совсем пакетная отработка но практически.
ну тогда действительно тут только отлавливать событие catch-ем.
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с)
С Уважением,
Елизаров Артем
Старый 25.08.2010, 16:57   #12  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 858 (32) +++++++
Регистрация: 15.01.2002
Адрес: Москва
Записей в блоге: 7
а что, если запись в лог делать в отдельном коннекшене, может тогда при ошибке записи лога его можно будет там же и отловить?

возникнет другая проблема, что при ошибке в основном процессе лог останется.
Старый 25.08.2010, 16:59   #13  
HorrR is offline
HorrR
Участник
 
340 / 30 (2) +++
Регистрация: 18.02.2008
Адрес: Киев
Цитата:
Сообщение от AndyD Посмотреть сообщение
Исключение внутри блока ttsbegin/ttscommit передает управление на следующий оператор после ttscommit самого верхнего уровня.
Т.е. обработчик должен выглядеть так
X++:
try
{
    ttsbegin;
    // что-то делаем
    ttscommit;
}
catch
{
    // обрабатываем исключение
}
Если у вам несколько вложенных ttsbegin/ttscommit, то исключения надо ловить на первом уровне
"Вот оно че, Михалыч"(с). Я то наивно думал, что по образу и подобию SEH реализованному например в С++ управление передается в ближайший блок Catch. А Аксапта оказывается по-другому хэндлит...

У меня то сам метод логгера именно так был оформлен:
X++:
try
{
    ttsbegin;
    // что-то делаем
    ttscommit;
}
catch
{
    // обрабатываем исключение
}
Но метод-то вызывался из процесса в котором уже была открыта транзакция, то есть в самом методе ttslevel уже был ненулевой. Спасибо!
__________________
Axapta has seduced me deadly!
Старый 25.08.2010, 17:00   #14  
titov is offline
titov
Участник
 
73 / 87 (3) ++++
Регистрация: 23.12.2005
Адрес: Казань
насколько я понял нужна целостность уникального по ключу процесса, который может быть запущен на нескольких клиентах, при этом если по ключу процесс выполнен, то не запускать процесс на другом клиенте. Тогда:
1. проверять дубликат до запуска процесса - а где-же еще
2. первый клиент может не завершить транзакцию, тогда отказ второго клиента от процесса - ошибка - то есть надо подождать разрешения ситуации
3. нужен некий семафор реальный или виртуальный - имеет статусы - выполняется, завершен - это и есть информация о том, что происходит

алгоритм вырисовывается такой - ключ - уникальный индекс
1. пока чужой семафор есть и статус = выполняется и время < тайм аута - ждем чем все кончится
2 если чужой семафор - завершено - выход
3. если нет чужого семафора - создать свой = выполняется
4. процесс до
5. лог
6. процесс после
7. семафор = завершено

технически наиболее близкое решение - это код выделения номеров по номерным сериям - 3 пункт это и есть выделить номер (ключ), только я имею ввиду не создавать номерную серию, а взять блоки кода по транзакциям - при разноске, например, документов сам процесс разноски еще не закоммичен, а вот номер уже использован и закоммичен!!! и другие клиенты об этом знают, там же есть моменты на предмет разрулить ситуацию, когда два клиента почти одновременно выполнят 3 пункт. Если 6 пункт не достигнут - надо в catch сбросить свой семафор.

семафором можно сделать саму таблицу логов - добавить статус

или - ADOConnection - читать незакомиченные (установить в команде уровень изоляции) записи лога (семафоры) другого клиента - а что?! здесь нет минуса первого варианта, а именно - если выключить комп на пункте 4, то .... семафор придеться чистить ручками или ваять нечто.

по любому главное - проверять процесс на запуск другим клиентом и ждать чем все там завершиться - придеться!

Последний раз редактировалось titov; 25.08.2010 в 17:06.
Старый 25.08.2010, 18:26   #15  
vallys is offline
vallys
Developer
 
146 / 108 (0) +++++
Регистрация: 18.01.2005
В аксапте в качестве семафора можно создать и использовать табличку, и вместо
X++:
log.insert();
поставить что-то вроде
X++:
select firstonly forupdate table where ...;
log.insert();
table = null;
Может и не совсем по ВР, за-то просто.
Старый 26.08.2010, 10:04   #16  
CDR is offline
CDR
MCTS
MCBMSS
 
236 / 175 (6) ++++++
Регистрация: 27.11.2003
Цитата:
Сообщение от HorrR Посмотреть сообщение
lev, ну точно так же на вскидку могу предположить, что если метод будет запущен одновременно, то и validateWrite в обоих случаях вернет true, так как дубликата на тот момент ещё не будет в базе.
Зависит от того, как вы реализуете блокирование ресурсов вашей таблицы логов при вставке/обновлении/удалении записей в ней.
__________________
Dynamics AX Experience
Старый 26.08.2010, 11:54   #17  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,277 / 3476 (122) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Вообще-то основная задача лога - это фиксировать события. Т.е. если событие в логе не фиксируется - то это "караул". Т.е. делать уникальный индекс на таблице логов - заведомо некорректно. Лучше потом выборку построить по каким-то критериям.
Потом, любое логирование какого-то события заведомо замедляет обработку этого события, в связи с чем на логируемую табличку (в рамках ускорения) нелогично накладывать какие-либо индексы.

Однако, я подозреваю, что тут не совсем логирование. Скорее всего тут - генерация осмысленных записей (используемых потом в рабочем процессе), которые логичным образом не должны дублироваться. В этом случае совет от titov как нельзя более лучшим образом подходит. Кстати - в качестве идеи - можно предложить подумать - а как же в АХ производится разноска журналов (из кода)? Два человека могут открыть ведь разнести документ? Ответ. При разноске (из кода) блокируется журнал, т.е. второй человек не может запустить разноску (из кода), если первый уже запустил ее.
В интерфейсе журнал блокируется при открытии строк журнала.


Наглядно в АХ работает процедура закрытия склада - в начале работы - в табличку InventClosing помещается запись о начале работы, а по завершению - статус записи обновляется.
__________________
Возможно сделать все. Вопрос времени
Теги
try/catch, исключения, как правильно, транзакции

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Вставка строк в таблицы Аксапты сторонними средствами Андре DAX: База знаний и проекты 1 07.05.2009 16:49
Множественная вставка записей Белов Владимир DAX: Программирование 9 16.10.2008 14:22
вывод количества записей в таблице на web форме и указание текущей страницы таблицы bambuk1960 DAX: Программирование 1 06.07.2006 13:27
Хранение отмеченных записей Pavel Pustovalov DAX: Программирование 9 17.05.2005 21:56
Вставка записей в аксапту из внешней БД Smith DAX: Программирование 2 20.09.2004 18:30

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 07:42.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.