![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Работаем с IB по сети [D5, IB6.x]
xmrz © (2003-05-27 00:22:00)Уважаемые мастера, помогите пожалуйста разобраться.
БД Yaffil на сервере, с ней работают 2 клиента, в основном вставка данных в таком виде :
/
SELECT ID FROM AUTOM WHERE (VIN = :VIN) AND (MODEL = :MODEL) INTO AID;
INSERT INTO DOC_POLICE (DATA,WHO_INS,SUMMA,OPERATION) VALUES (:INDATA,:INS,:SUMDAY,1);
SELECT MAX(ID) FROM DOC_POLICE WHERE (OPERATION=1) AND (WHO_INS=:INS) INTO PID;
INSERT INTO INOUT (IO_MOMENT,DATA,WHO_INS,FIO,AUTOM,OPERATION,DOC_ID)
VALUES (:MOMENT,:INDATA,:INS,:FIO,:AID,1,:PID);
\
В таблицах ID генерируются с помощью триггеров и генераторов BEFORE INSERT.
Таблицы - как видно имеют зависимости : ID из AUTOM и DOC_POLICE подставляются в INOUT.
Выполнение всех вышеперечисленных операций вызывается из одной процедуры, после вызова
процедуры клиентом сразу делается Transaction.Commit.
Опция ForcedWrites базы была выключена. Через какое-то время стали прооисходить сбои при
отключении эл. энергии, причём сервер не выключался, только клиенты. Сбои заключались в том, что
после возобновления питания в таблице INOUT записи вставленные с разных клиентов имели
один и тот же ID из табл. DOC_POLICE. А в DOC_POLICE оказывались 2 одинаковых ID, хотя по этому полю
создан уникальный индекс!
После включения ForcedWrites при сбоях с питанием таких вещей вроде не происходит, но зато безо всяких
на то причин стали появляться "пропуски" в таблицах DOC_POLICE и INOUT, т.е. триггер генерирует значения
вхолостую. Если бы я где то делал RollBack или где то во время выполнения ХП выскакивали Access Violation...
было бы всё понятно... В чём может быть причина, поделитесь пожалуйста своими соображениями.
Sergey13 (2003-05-27 11:44:00) [1]2xmrz (27.05.03 11:13)
Если уж так важен номер без пропусков, то раздели в базе (и главное в голове) понятия ID и порядковый номер. Первое заполняется генератором и пропуски там пофигу. Второе можно обработать в тригере после вставки - проапдейтить поле номера как max(nomer)+1 с анализом того что такой номер уже может быть создан другим юзером. Для гарантии на номер тоже можно (нужно) повесить уникальность, особливо с признаком года, например, для нумерации по году.
Danilka (2003-05-27 11:22:00) [2]xmrz (27.05.03 11:13)
блокировка, max+1, запись и завершение транзакции - в одной процедуре, доли секунд, юзера и не заметят ничего.
Zacho (2003-05-27 11:21:00) [3]
> xmrz (27.05.03 11:13)
Например, такой алгоритм.
После заполнения формы стартуется отдельная транзакция, в которой и происходит блокировка, получения номера и вставка данных. Если транзакция будет достаточно короткой, а операторов - не много, то может быть замедление работы будет практически незаметно.
xmrz (2003-05-27 11:13:00) [4]К сожалению блокировать таблицы нельзя, так как перед нажатием "Ok" при заполнении формы в Edit"ах и ComboBox"ах на onExit повешаны небольшие запросы, помогающие оператору заполнить форму и контролирующие некоторые параметры по бизнес-логике (для отлова попыток мошенничества) эти запросы тоже выполняются из ХП и возращают по 1..6 значений, но читают они из тех же таблиц. А если заблокировать таблицы на чтение, то работа грозит превратиться действительно в "однопользовательскую"?
Danilka (2003-05-27 11:04:00) [5]xmrz (27.05.03 10:59)
тогда, вероятно, только вот этот вариант:
Zacho © (27.05.03 10:59)
стартовать транзакцию, вставлять данные и завершать транзакцию в одной процедуре, перед печатью.
xmrz (2003-05-27 10:59:00) [6]Дело в том, что с этими номерами тут же распечатываются квитанции. "Покупатель" уходит с квитанцией на руках, и через неизвестное количество дней возвращается. Даёт квитанцию, оператор вносит номер квитанции и от этого отталкиваются денежные расчёты... Пропуски мешают "контролирующему органу", а ему про триггеры объяснять... ну в общем такая ситуация.
Zacho (2003-05-27 10:59:00) [7]
> xmrz (27.05.03 10:47)
Если нужна автоматически генерируемая последовательность номеров без пропусков, то сделать это можно следующим образом:
Стартуем транзакцию. При созданием нового документа блокируем таблицу (в том числе на чтение). Получаем MAX(ID)+1. Создаем документ, INSERT, Commit.
Естественно, редактировать номера и удалять документы - запрещаем.
Недостаток: это практически "однопользовательский" режим работы. При интенсивной работе нескольких операторов возможны приличные торможения. Задержки можно свести к минимуму, если получать номер непосредственно перед вставкой, в как можно более короткой транзакции.
Danilka (2003-05-27 10:49:00) [8]xmrz (27.05.03 10:47)
а когда нужна эта гарантированая последовательность?
если для отчетов, то ее можно генерировать во время отчета.
честно говоря, не знаю, в остальном чем могут помешать пропуски.
xmrz (2003-05-27 10:47:00) [9]Проблема возникла именно в пик работы операторов. Так что на select Max(ID) .. надеяться особо не приходится
Danilka (2003-05-27 10:42:00) [10]xmrz (27.05.03 10:38)
Вообще-то гарантированая последовательность номеров нужна только юзерам, в любых других случаях можно обойтись. Пусть они этим и занимаются. :))
А Max(ID) - очень вероятен глюк на нескольких пользователях, когда два или больше юзеров сделали max(id) в транзакциях, стартовавших примерно в одно время.
Alexandr (2003-05-27 10:40:00) [11]по разному можно в зависимости от задачи и от необходимости
xmrz (2003-05-27 10:38:00) [12]Тогда может порекомендуете механизм гарантирующий генерацию последовательных номеров? Использовать select Max(ID) ...?
Alexandr (2003-05-27 10:33:00) [13]какую проблему?
Danilka (2003-05-27 10:33:00) [14]xmrz (27.05.03 10:25)
Два раза уже сказал Alexandr ©, скажу третий раз: не надо привязываться к значениям генератора. Это не его задача.
xmrz (2003-05-27 10:25:00) [15]Что сможет решить эту проблему в принципе? Переход на трёхзвенную сруктуру? Кусок клиента отвечающий за запуск процедур вынести на сервер? Не работал раньше с Midas, даже страшно как то... :(
Alexandr (2003-05-27 10:16:00) [16]ну и что. Все равно нормально будет.
а главная идея - не закладываться вообще на поледовательность значений формируемых генератором и принять пропуски как должное.
Да и вот еще. Если процедуру вызываешь на клиенте и спользуешь IBX , то возможен при определенных обстоятельствах двукратный вызов процедуры.
xmrz (2003-05-27 10:12:00) [17]> Alexandr © (27.05.03 09:55)
Я и сам сначала подумал про питание, но всвязи с тем что имею возможность реально следить за временем понимаю что искать ошибку надо в другом месте. Поэтому и решил обратиться за помощью к людям :)
А если теоретически предположить что запросы от двух клиентов пришли одновременно? Процедура ведь тяжёлая, UDF используются?
Ну хоть какие нибудь идеи?!
Alexandr (2003-05-27 09:55:00) [18]не бывает так.
ну не может генератор сам увеличиться...
xmrz (2003-05-27 09:46:00) [19]1) Генераторы получают новые значения автоматически при вставке новой записи:
SET TERM ^ ;
CREATE TRIGGER SET_INOUT_ID FOR INOUT
BEFORE INSERT AS
BEGIN
NEW.ID = GEN_ID(INOUT_GEN, 1);
END^
SET TERM ;^
2) Питание на тот момент не выключалось. Я слежу за временем, когда выполняются операции в IO_MOMENT
Danilka (2003-05-27 09:37:00) [20]гы, может я глючу, но в упор не вижу где здесь дергается генератор.
даже поиск по gen_id делал...