Какой наименее навязчивый механизм блокировки я могу использовать для предотвращения вставки строк в таблицу Oracle? - PullRequest
2 голосов
/ 17 февраля 2010

У меня определены родительские / дочерние отношения, которые, к сожалению, невозможно поддерживать с помощью внешнего ключа.Родители и дети хранятся в одной таблице.Родительские / дочерние отношения идентифицируются столбцом «ITEM_ID».Дочерний ITEM_ID состоит из его родительского ITEM_ID, а затем того, что мы можем эффективно рассматривать как уникальный идентификатор дочернего элемента в этом родительском элементе.

Я реализую процедуру PL / SQL для удаления записей из этой таблицы ITEM.Первая часть процедуры проверяет наличие каких-либо детей;в этом случае возникает ошибка приложения (имитирующая внешний ключ).

Мне интересно, как предотвратить вставку дочерних записей другим процессом в промежутке времени, когда курсор в моей процедуре удаления заполнен и заблокирован? "FOR UPDATE "и точка, в которой родительская запись фактически удалена.

Нужно ли блокировать всю эту таблицу во время этого процесса?

Или я должен изменить процедуру вставки, чтобы выбратьродительская запись «ЗА ОБНОВЛЕНИЕ»?

ОБНОВЛЕНИЕ: Я создал приведенный выше пример просто для описания общей ситуации, но для обоснования проблемы с внешним ключом / ограничением, я приведу фактическую / болеесложная структура ниже:

В удаленной базе данных есть несколько таблиц: COMPANY, BUILDING, FLOOR.В нашей организации этажи принадлежат зданиям, а здания - компаниям.

Приложение, над которым я работаю, связывает роли с сотрудниками.Таблица, которая связывает Employee (идентификатор сотрудника) с ролью (Role ID), также имеет столбец «Расположение».Столбец location соответствует идентификатору одной из таблиц удаленной базы данных, и мы определяем, к какой таблице он принадлежит, на основе столбца Type в таблице Role.

Например, вот несколько записей из моей таблицы:

Role = Janitor
Type = BUILDING
Location = COMPANY1-BUILDING1
Parent Role = Manager


Role = Manager
Type = COMPANY
Location = COMPANY1
Parent Role = CEO

Как вы можете догадаться, идентификаторы этажей имеют формат company-building-floor в таблице удаленной базы данных.

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

Ответы [ 4 ]

4 голосов
/ 17 февраля 2010

Если процесс удаления получит простую блокировку родительской записи, это не помешает вставить дочерние записи. Блокировка всей таблицы может серьезно сериализовать ваше приложение.

Поэтому принудительный процесс вставки в SELECT ... FOR UPDATE для родительской записи и процесс удаления для блокировки родительской записи - ваш единственный выбор. Основная проблема этой реализации заключается в том, что ее легко обойти. Или, другими словами, каждый процесс, который взаимодействует с таблицей, должен будет выполнить эти дополнительные блокировки.

2 голосов
/ 17 февраля 2010

Как уже упоминалось в APC, существует проблема с моделью данных. Правильный способ моделирования такого рода иерархических данных:

key_field            [data_type] primary key
parent_key_field     [data_type] null foreign key references key_field

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

Тем не менее, если вы откроете курсор с помощью SELECT FOR UPDATE для своей таблицы, он должен блокировать только те строки, которые вы хотите удалить. Вы не можете запретить кому-либо «ссылаться» на эту таблицу в вашем «внешнем ключе», потому что ITEM_ID - это просто другое значение.

Что может сработать, встраивая это:

procedure delete_me (p_item_key)
as
  l_child_count number;
begin
  -- verify the value being deleted exists and has no children as you already do

  delete from tbl a
   where not exists (select null
                       from tbl b
                      where b.item_id = a.item_id)
  if sql%rowcount = 0 then
    -- your delete failed; raise an error.
  end if;
end;
1 голос
/ 18 февраля 2010

Усиление комментариев APC об изменении каждого процесса, вот одно из осложнений.

предотвращение записи дочерних записей вставлен другим процессом между время курсора в моем удалении процедура заполнена и заблокирована "ЗА ОБНОВЛЕНИЕ ", и точка, в которой родительская запись фактически удалена.

Помните, что дочерняя запись, возможно, уже была вставлена ​​(но не зафиксирована) при попытке заблокировать родителя. Если процесс вставки дочерней записи также не снимает эксклюзивную блокировку с родителя (предотвращая блокировку при удалении), он не будет работать. Поскольку только одна транзакция может иметь эксклюзивную блокировку для строки за раз, это будет сериализовать вставки.

Вопрос, с которым вы сталкиваетесь, заключается в том, окажете ли вы большее влияние на ваше приложение, сериализовав вставки под родительским элементом или заблокировав всю таблицу на время транзакции удаления. Если ваше удаление происходит редко и транзакция выполняется быстро, я бы выбрал блокировку таблицы как простейшую реализацию.

1 голос
/ 17 февраля 2010

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

Мне любопытно, почему вы говорите, что это не может быть реализовано ограничением внешнего ключа?

...