неудобный constraint -- как обеспечить?

Vladimir Dozen
Дата: 30.08.2003 14:39:11
Ситуация -- есть теблица (А), ссылающаяся на другую (Б), причем
есть бизнес-условие, что число записей в Б, которые привязаны к одной
записи в А, должно быть не больше, чем указано в одном из аттрибутов А.

Чтобы было понятнее: в реальном мире А -- это некая кормушка, имеющая
N сосок. Аггрегаты Б ищут себе кормушку, и, найдя, цепляются к соске.
Разумеется, к А не может быть прицеплено больше Б-шек, чем есть сосок
у А. Число сосок у А от 2 до бесконечности, но практически -- не более 64.

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

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

Возникла мысль, что чем-то могут помочь триггера. Но, насколько я понимаю, триггера точно так же пашут внутри транзакции, и узнать, что в параллельной транзакции уже присосались -- не может. Или я неправ?

Мысли, идеи?
Stellar.
Дата: 01.09.2003 09:57:41

LOCK TABLES
Просто Миша
Дата: 05.09.2003 17:27:49
BEGIN;
SELECT * from table_a where table_a.maxlink - (SELECT count(*) from table_b where table_a.link_down = table_b.link_up) > 0 FOR UPDATE;


INSERT into table_b (link_up) VALUES (то значение link_down из таблицы table_a, которое мы получили в предыдущем запросе);

COMMIT;

Смысл в том, что параллельный процесс на этом же куске зависнет на этом самом FOR UPDATE. И будет висеть до тех пор пока ты не сделаешь COMMIT
Пупкин
Дата: 05.09.2003 18:31:43
Спасибо за наводку.
Действительно в селекте есть возможность прописать:
[ FOR UPDATE [ OF update_table [, ...] ] ]

где:
/*
FOR UPDATE
The locking clause that places an implicit ROW SHARE MODE lock (see LOCK") on the from_item table selected in the current transaction.

OF update_table
A specific table to which to apply ROW SHARE MODE locking when multiple tables are selected in the FROM clause.
*/