Не понятное поведение foreign key

Access Violation, некорректное выполнение запросов или вызовов API, ошибки утилит командной строки, в общем все, что вам мешает работать

Модераторы: kdv, dimitr

AL-GALI
Сообщения: 25
Зарегистрирован: 03 янв 2007, 15:24

Не понятное поведение foreign key

Сообщение AL-GALI » 07 янв 2007, 01:36

Возможно это и не баг, но данная особенность нигде не описана... (буду честнее - не встречал такого описания)

Использовался 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. Это нормальное поведение?

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Сообщение hvlad » 07 янв 2007, 01:44

Это не баг, но особенность - нельзя ссылаться на активную запись.
Ибо, вообще говоря, неизвестно - менялся ли в ней PK, сколько раз и как будет завершена тр-ция

AL-GALI
Сообщения: 25
Зарегистрирован: 03 янв 2007, 15:24

Сообщение AL-GALI » 07 янв 2007, 01:53

hvlad писал(а):Это не баг, но особенность - нельзя ссылаться на активную запись.
Ибо, вообще говоря, неизвестно - менялся ли в ней PK, сколько раз и как будет завершена тр-ция
Спасибо за ответ!
Вообще, почему мне это понадобилось: это часть платежной системы. Имеется несколько "балансов" на стороне-провайдере услуг (удаленная сторона) и сами платежи (поступают в платежную систему). Балансы запрашиваются у удаленной стороны (с интервалом 1..3 минуты) и обновляются в главной таблице (асинхронно), в то же время продолжается процесс обработки входящих платежей (как раз таки insert). Как только денег на данном балансе становится мало, платежи начинают приниматься в счет другого баланса. Вот как раз там-то это и всплыло, когда insert вызвал "lock conflict on no wait transaction". Для меня сие было большой неожиданностью. :)

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Сообщение hvlad » 07 янв 2007, 02:00

Можно попробовать вставлять дочерние записи в wait тр-ции

AL-GALI
Сообщения: 25
Зарегистрирован: 03 янв 2007, 15:24

Сообщение AL-GALI » 07 янв 2007, 02:02

Кстати, если на PAYMENTS сделать ссылку из другой (третьей) таблицы, то insert в эту третью таблицу с foreign key, ссылающемся на запись в PAYMENTS, которая ссылается на активную запись в MAIN срабатывает без ошибок... Я совсем запутался.

fb.bird
Сообщения: 13
Зарегистрирован: 26 окт 2007, 11:57

Сообщение fb.bird » 28 фев 2008, 17:42

В 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.

Кузнецов Евгений
Сообщения: 144
Зарегистрирован: 16 фев 2006, 22:36

Сообщение Кузнецов Евгений » 28 фев 2008, 18:12

Доброго времени суток!
fb.bird писал(а):В FireBird 2.1 будет реализована возможность создания Foreign Key без монопольной блокировки базы целиком.
Это сделано уже в 2.0. Просто в 2.1 RC1 Release Notes объединены.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 29 фев 2008, 00:52

to fb.bird - при чем тут немонопольное создание FK? Вы вопрос читали, внимательно?

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 29 фев 2008, 11:01

AL-GALI писал(а):Кстати, если на PAYMENTS сделать ссылку из другой (третьей) таблицы, то insert в эту третью таблицу с foreign key, ссылающемся на запись в PAYMENTS, которая ссылается на активную запись в MAIN срабатывает без ошибок... Я совсем запутался.
Чего тут путаться?
Вроде всё ясно - из PAYMENTS мы ссылаемся на запись в MAIN, которая в данный момент "мутирует".
Но сама-то запись в PAYMENTS считается корректной, её никто сейчас не меняет, почему мы не можем на неё ссылаться-то?

fb.bird
Сообщения: 13
Зарегистрирован: 26 окт 2007, 11:57

Сообщение fb.bird » 29 фев 2008, 16:20

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 - архитектура множественных поколений записей) объясняет и подтверждает данную особенность.
Иначе и нельзя, иначе будет полный бардак.

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Сообщение hvlad » 29 фев 2008, 16:32

fb.bird писал(а):Радуйтесь что Вы не работаете в MS-SQL 2000 и ниже, где Вы не сможете изменить или вставить данные в таблицу, которая в данный момент читается или же не сможете читать данные из таблицы, которая в данный момент апдейтится или в нее вставляются данные, ибо в них блокировка часто идёт на уровне таблицы и только в FireBird на уровне блока или записи.
Только первое слово имеет отношение к истине

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 29 фев 2008, 16:50

[quote="fb.bird"][/quote]
Хватит уже ахинею нести, к делу не относящуюся в особенности.

Hint: со скулем многие тут сталкивались и работали. (и с оракулом тоже)

fb.bird
Сообщения: 13
Зарегистрирован: 26 окт 2007, 11:57

Сообщение fb.bird » 29 фев 2008, 17:10

WildSery писал(а): Хватит уже ахинею нести, к делу не относящуюся в особенности.
Ахинею!?
По-Вашему это нормально, когда пытаются вставить (из транзакции номер 2) запись со значением в поле, которое используется как ключ для апдейта в незавершенной транзакции номер 1 ?

Я понимаю, почему этот форум посещает так мало людей. Одна из причин наличие таких грубиянов как WildSery, которые находятся тут в статусе "заслуженного разработчика". Для них правила не действуют. Возможно блатные :).
kdv, можете меня забанить за покушение на такого крутого мэна, каг WildSery, проживу как-нибудь без этого форума, в конце-концов есть форумы по Firebird на буржуйском.
Последний раз редактировалось fb.bird 29 фев 2008, 17:17, всего редактировалось 1 раз.

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 29 фев 2008, 17:13

fb.bird писал(а): По-Вашему это нормально, когда пытаются вставить (из транзакции номер 2) запись со значением в поле, которое используется как ключ для апдейта в незавершенной транзакции номер 1 ?
Сам-то понял чо сказать хотел?
fb.bird писал(а): проживу как-нибудь без этого форума, в конце-концов есть форумы по Firebird на буржуйском.
Вставая на колени, заламывая руки и плача: не покидай нас, милый!

fb.bird
Сообщения: 13
Зарегистрирован: 26 окт 2007, 11:57

Сообщение fb.bird » 29 фев 2008, 17:22

Merlin писал(а):Сам-то понял чо сказать хотел?
А ты вообще лох,
вместо того чтобы написать что конкретно в моих словах неправильно,
ты использовал эту избитую, не проясняющую твоих мыслей фразу.
И ты лох вдвойне, потому что вмешиваешься в момент когда у меня идут разборки с другим.
Последний раз редактировалось fb.bird 29 фев 2008, 17:27, всего редактировалось 1 раз.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 29 фев 2008, 17:22

Оффтоп:

Да мне плевать, что обо мне думают незнакомые мне люди.
Если ты думаешь, что у нас с тобой "разборки", ты ошибаешься. Мне нет до тебя дела.
И кстати я не любимчик kdv, меня он точно так же по шапке хлопнет, если посчитает, что меня заносит.

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 29 фев 2008, 17:43

fb.bird писал(а): А ты вообще лох,
Открыл Америку. Про это даже на одном сарае написано.
fb.bird писал(а): вместо того чтобы написать что конкретно в моих словах неправильно,
А Х его З что конкретно там вообще написано, а не то что неправильно.
fb.bird писал(а): И ты лох вдвойне, потому что вмешиваешься в момент когда у меня идут разборки с другим.
Простите, Ваше Величество, сразу не признал :roll:

belov-evgenii
Сообщения: 52
Зарегистрирован: 28 сен 2007, 10:19

Сообщение belov-evgenii » 02 мар 2008, 13:01

Приди же, модератор.

stix-s
Заслуженный разработчик
Сообщения: 557
Зарегистрирован: 13 дек 2005, 11:52

Сообщение stix-s » 03 мар 2008, 06:50

хых, похоже народ в пятницу оторвался :)

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 03 мар 2008, 09:59

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

Ответить