Страница 1 из 2
Не понятное поведение foreign key
Добавлено: 07 янв 2007, 01:36
AL-GALI
Возможно это и не баг, но данная особенность нигде не описана... (буду честнее - не встречал такого описания)
Использовался IBExpert, FB 2.0.12748-win32 на win2003
Имеем две таблицы (приведу скрипт так, как его показывает ibexpert за искл. комментариев, возможно, что это важно):
Первая таблица:
Код: Выделить всё
SET SQL DIALECT 3;
CREATE GENERATOR GEN_MAIN_ID;
CREATE TABLE MAIN (
ID INTEGER NOT NULL,
BALANCE DECIMAL(15,2) DEFAULT 0.00 NOT NULL
);
ALTER TABLE MAIN ADD CONSTRAINT PK_MAIN PRIMARY KEY (ID);
SET TERM ^ ;
/* Trigger: MAIN_BI */
CREATE TRIGGER MAIN_BI FOR MAIN
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.ID IS NULL) THEN
NEW.ID = GEN_ID(GEN_MAIN_ID,1);
END
^
SET TERM ; ^
Вторая таблица:
Код: Выделить всё
SET SQL DIALECT 3;
CREATE GENERATOR GEN_PAYMENTS_ID;
CREATE TABLE PAYMENTS (
ID INTEGER NOT NULL,
ID_MAIN INTEGER NOT NULL,
MONEY DECIMAL(15,2) NOT NULL
);
ALTER TABLE PAYMENTS ADD CONSTRAINT PK_PAYMENTS PRIMARY KEY (ID);
ALTER TABLE PAYMENTS ADD CONSTRAINT FK_PAYMENTS_1 FOREIGN KEY (ID_MAIN) REFERENCES MAIN (ID) ON DELETE CASCADE ON UPDATE CASCADE;
SET TERM ^ ;
/* Trigger: PAYMENTS_BI */
CREATE TRIGGER PAYMENTS_BI FOR PAYMENTS
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.ID IS NULL) THEN
NEW.ID = GEN_ID(GEN_PAYMENTS_ID,1);
END
^
SET TERM ; ^
Добавляем в MAIN записи (одну, например):
Код: Выделить всё
INSERT INTO MAIN (ID, BALANCE) VALUES (1, 2325);
Здесь можно было не указывать ID и 1, ну да уж как получилось. Далее COMMIT этой транзакции.
В PAYMENTS добавляем одну запись:
Код: Выделить всё
INSERT INTO PAYMENTS (ID, ID_MAIN, MONEY) VALUES (1, 1, 200);
Далее снова COMMIT этой транзакции. Все нормально.
Теперь начинаем транзакцию и обновляем баланс
Код: Выделить всё
update main set balance = balance + 120 where id = 1
Транзакцию пока не завершаем!
Начинаем другую транзакцию (в другом или этом же коннекте) и делаем
Код: Выделить всё
update payments set money = 0 where id_main = 1
Все нормально, ошибок нет. Но, если мы сделаем
Код: Выделить всё
insert into payments (id_main, money) values (1, 0)
То получим ошибку:
Код: Выделить всё
Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements.
lock conflict on no wait transaction.
violation of FOREIGN KEY constraint "FK_PAYMENTS_1" on table "PAYMENTS".
Foreign key reference target does not exist.
А мне очень хочется что-то подобное делать! Пока что просто убрал foreign key. Это нормальное поведение?
Добавлено: 07 янв 2007, 01:44
hvlad
Это не баг, но особенность - нельзя ссылаться на активную запись.
Ибо, вообще говоря, неизвестно - менялся ли в ней PK, сколько раз и как будет завершена тр-ция
Добавлено: 07 янв 2007, 01:53
AL-GALI
hvlad писал(а):Это не баг, но особенность - нельзя ссылаться на активную запись.
Ибо, вообще говоря, неизвестно - менялся ли в ней PK, сколько раз и как будет завершена тр-ция
Спасибо за ответ!
Вообще, почему мне это понадобилось: это часть платежной системы. Имеется несколько "балансов" на стороне-провайдере услуг (удаленная сторона) и сами платежи (поступают в платежную систему). Балансы запрашиваются у удаленной стороны (с интервалом 1..3 минуты) и обновляются в главной таблице (асинхронно), в то же время продолжается процесс обработки входящих платежей (как раз таки insert). Как только денег на данном балансе становится мало, платежи начинают приниматься в счет другого баланса. Вот как раз там-то это и всплыло, когда insert вызвал "lock conflict on no wait transaction". Для меня сие было большой неожиданностью.

Добавлено: 07 янв 2007, 02:00
hvlad
Можно попробовать вставлять дочерние записи в wait тр-ции
Добавлено: 07 янв 2007, 02:02
AL-GALI
Кстати, если на PAYMENTS сделать ссылку из другой (третьей) таблицы, то insert в эту третью таблицу с foreign key, ссылающемся на запись в PAYMENTS, которая ссылается на активную запись в MAIN срабатывает без ошибок... Я совсем запутался.
Добавлено: 28 фев 2008, 17:42
fb.bird
В FireBird 2.1 будет реализована возможность создания Foreign Key без монопольной блокировки базы целиком.
Creating Foreign Key Constraints No Longer Requires Exclusive Access
V. Horsun
Now it is possible to create foreign key constraints without needing to get an exclusive lock on the whole
database.
Добавлено: 28 фев 2008, 18:12
Кузнецов Евгений
Доброго времени суток!
fb.bird писал(а):В FireBird 2.1 будет реализована возможность создания Foreign Key без монопольной блокировки базы целиком.
Это сделано уже в 2.0. Просто в 2.1 RC1 Release Notes объединены.
Добавлено: 29 фев 2008, 00:52
kdv
to fb.bird - при чем тут немонопольное создание FK? Вы вопрос читали, внимательно?
Добавлено: 29 фев 2008, 11:01
WildSery
AL-GALI писал(а):Кстати, если на PAYMENTS сделать ссылку из другой (третьей) таблицы, то insert в эту третью таблицу с foreign key, ссылающемся на запись в PAYMENTS, которая ссылается на активную запись в MAIN срабатывает без ошибок... Я совсем запутался.
Чего тут путаться?
Вроде всё ясно - из PAYMENTS мы ссылаемся на запись в MAIN, которая в данный момент "мутирует".
Но сама-то запись в PAYMENTS считается корректной, её никто сейчас не меняет, почему мы не можем на неё ссылаться-то?
Добавлено: 29 фев 2008, 16:20
fb.bird
kdv писал(а):to fb.bird - при чем тут немонопольное создание FK? Вы вопрос читали, внимательно?
Ой.

Похоже это был офтопик. Прошу прощения.
А насчет
AL-GALI писал(а):возможно это и не баг, но данная особенность нигде не описана... (буду честнее - не встречал такого описания)
Как это не встречали? Встречали, да еще как.
Когда Вы вызвали
Код: Выделить всё
update payments set money = 0 where id_main = 1
Вы захватили запись с id_main = 1 на update, тем самым заблокировав её от каких бы то ни было update-ов, insert-ов других транзакций.
Пока Ваша
эта транзация не завершена, никому не будет позволено апдейтить эту запись, а возможно даже соседние, если они находятся с ней в одном блоке, если блокировка идёт на уровне блока.
Поэтому данное поведение сервера вполне очевидно и вполне понятно.
Радуйтесь что Вы не работаете в MS-SQL 2000 и ниже, где Вы не сможете изменить или вставить данные в таблицу, которая в данный момент читается или же не сможете читать данные из таблицы, которая в данный момент апдейтится или в нее вставляются данные, ибо в них блокировка часто идёт на уровне таблицы и только в FireBird на уровне блока или записи.
Любая статья про уровни изоляции транзакций в СУБД с архитектурой MGA (Multi Generation Architecture - архитектура множественных поколений записей) объясняет и подтверждает данную особенность.
Иначе и нельзя, иначе будет полный бардак.
Добавлено: 29 фев 2008, 16:32
hvlad
fb.bird писал(а):Радуйтесь что Вы не работаете в MS-SQL 2000 и ниже, где Вы не сможете изменить или вставить данные в таблицу, которая в данный момент читается или же не сможете читать данные из таблицы, которая в данный момент апдейтится или в нее вставляются данные, ибо в них блокировка часто идёт на уровне таблицы и только в FireBird на уровне блока или записи.
Только первое слово имеет отношение к истине
Добавлено: 29 фев 2008, 16:50
WildSery
[quote="fb.bird"][/quote]
Хватит уже ахинею нести, к делу не относящуюся в особенности.
Hint: со скулем многие тут сталкивались и работали. (и с оракулом тоже)
Добавлено: 29 фев 2008, 17:10
fb.bird
WildSery писал(а):
Хватит уже ахинею нести, к делу не относящуюся в особенности.
Ахинею!?
По-Вашему это нормально, когда пытаются вставить (из транзакции номер 2) запись со значением в поле, которое используется как ключ для апдейта в
незавершенной транзакции номер 1 ?
Я понимаю, почему этот форум посещает так мало людей. Одна из причин наличие таких грубиянов как
WildSery, которые находятся тут в статусе "заслуженного разработчика". Для них правила не действуют. Возможно блатные

.
kdv, можете меня забанить за покушение на такого крутого мэна, каг
WildSery, проживу как-нибудь без этого форума, в конце-концов есть форумы по Firebird на буржуйском.
Добавлено: 29 фев 2008, 17:13
Merlin
fb.bird писал(а):
По-Вашему это нормально, когда пытаются вставить (из транзакции номер 2) запись со значением в поле, которое используется как ключ для апдейта в незавершенной транзакции номер 1 ?
Сам-то понял чо сказать хотел?
fb.bird писал(а):
проживу как-нибудь без этого форума, в конце-концов есть форумы по Firebird на буржуйском.
Вставая на колени, заламывая руки и плача: не покидай нас, милый!
Добавлено: 29 фев 2008, 17:22
fb.bird
Merlin писал(а):Сам-то понял чо сказать хотел?
А ты вообще лох,
вместо того чтобы написать что конкретно в моих словах неправильно,
ты использовал эту избитую, не проясняющую твоих мыслей фразу.
И ты лох вдвойне, потому что вмешиваешься в момент когда у меня идут разборки с другим.
Добавлено: 29 фев 2008, 17:22
WildSery
Оффтоп:
Да мне плевать, что обо мне думают незнакомые мне люди.
Если ты думаешь, что у нас с тобой "разборки", ты ошибаешься. Мне нет до тебя дела.
И кстати я не любимчик kdv, меня он точно так же по шапке хлопнет, если посчитает, что меня заносит.
Добавлено: 29 фев 2008, 17:43
Merlin
fb.bird писал(а):
А ты вообще лох,
Открыл Америку. Про это даже на одном сарае написано.
fb.bird писал(а):
вместо того чтобы написать что конкретно в моих словах неправильно,
А Х его З что конкретно там вообще написано, а не то что неправильно.
fb.bird писал(а):
И ты лох вдвойне, потому что вмешиваешься в момент когда у меня идут разборки с другим.
Простите, Ваше Величество, сразу не признал

Добавлено: 02 мар 2008, 13:01
belov-evgenii
Приди же, модератор.
Добавлено: 03 мар 2008, 06:50
stix-s
хых, похоже народ в пятницу оторвался

Добавлено: 03 мар 2008, 09:59
kdv
проживу как-нибудь без этого форума
А ты вообще лох,
И ты лох вдвойне, потому что вмешиваешься в момент когда у меня идут разборки с другим.
to fb.bird - предупреждение. удалять логин пока не буду.