Параллелизм функций Oracle

В настоящее время у меня есть INSERT TRIGGER, который в Oracle 10g запускает пользовательскую функцию, которая генерирует забавный буквенно-цифровой код, который используется как часть вставки.

Мне действительно нужно убедиться, что функция (или даже триггер) является потокобезопасной, чтобы, если два пользователя одновременно активировали триггер, функция, используемая в триггере, НЕ возвращала один и тот же код для обоих пользователей.

Поток в триггере следующий:

НАЧАЛО

  1. определить, нужно ли нам продолжать на основе бизнес-логики
  2. запустите пользовательскую функцию, чтобы получить новый код
  3. использовать возвращенный код как вставку в другую таблицу

КОНЕЦ

Основная проблема заключается в том, что во время выполнения шага 2 отдельный поток запускает триггер, который также попадает на шаг 2 и возвращает тот же код, что и первый поток. (Я понимаю, что это очень напряженная ситуация, но нам нужно с этим справиться).

Я подумал о двух основных способах сделать это:

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

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

Моя идея не идеальна, но она должна работать, однако я хотел бы услышать от любого, у кого могут быть лучшие идеи, чем это!

Большое спасибо за любую оказанную помощь.

Привет, Марк


person Mark    schedule 15.12.2008    source источник
comment
На шаге 2 вы выбираете или обновляете какие-либо таблицы? Что он использует для управления возвращаемыми кодами? Sysdate, или какое-то табличное значение, или внешняя функция C, или что?   -  person WW.    schedule 11.01.2009


Ответы (3)


Здесь не нужно работать над эксклюзивностью. Oracle делает это, управляя вашими транзакциями.

Суть в том, что каждый вызов вашей «настраиваемой функции» должен возвращать уникальный код.

Это означает НЕ использование системной даты/времени, а что-то еще для обеспечения уникальности.

Я рекомендую это:

select sys_guid() from dual;

Используйте sys_guid(), чтобы посолить свою функцию, и все должно быть хорошо в триггерной стране.

Только ПОЖАЛУЙСТА, не пытайтесь обновить другую таблицу с этим значением, иначе вам придется иметь дело с мутирующими таблицами и тому подобным.

Изменить. Очевидно, как уже упоминалось несколько других, использование последовательности в триггере для заполнения вашей функции является еще одним хорошим предложением, поскольку Oracle обеспечивает уникальность. Однако использование его в качестве начального значения может привести к предсказуемому результату, поэтому будьте осторожны, если «настраиваемая функция» — это сброс пароля или что-то в этом роде.

person BQ.    schedule 15.12.2008
comment
Хороший ответ. Еще один вариант уникального значения — простая последовательность, которая никогда не возвращает одно и то же значение дважды, вне зависимости от транзакций, откатов и так далее. - person Dan Vinton; 16.12.2008
comment
Последовательность была бы отличной, однако мне нужно сгенерировать буквенно-цифровой код для бизнеса в моей функции... можете ли вы сделать это как какую-то пользовательскую последовательность? - person Mark; 16.12.2008
comment
@BQ, что ты имеешь в виду под солью своей функции? Не могли бы вы уточнить подробнее? Спасибо. - person Mark; 16.12.2008
comment
Если вы описываете буквенно-цифровой код, характерный для вашего бизнеса, нам, возможно, не придется так много гадать. :) - person dkretz; 16.12.2008
comment
Вам вообще не нужно знать, что это такое, это просто код, который генерирует функция, вопрос был в том, можете ли вы создать пользовательскую последовательность, которая использует эту функцию вместо стандартного числового приращения. - person Mark; 16.12.2008
comment
@ Марк, во-вторых, вы говорите о том, что делаете разные вещи в БД в разных потоках, вы на неправильном пути. СУБД созданы для обработки параллелизма за вас. - person BQ.; 16.12.2008
comment
@Mark, соление просто предоставляет значение, которое делает вашу функцию зависимой от чего-то другого, кроме пользовательского ввода, поэтому вы можете гарантировать, что разные транзакции получат уникальные значения. Случайное число может привести к дублированию, но guid этого не делает.... но мы угадываем коды, которые вы хотите вернуть. - person BQ.; 16.12.2008
comment
@BQ, спасибо за информацию, я понимаю, что вы имеете в виду, однако моя проблема в том, что функция читает из таблицы как часть своего алгоритма для генерации нового кода, и если я запускаю две вставки одновременно, алгоритм генерирует тот же код :( однако применение эксклюзивной блокировки помогает... - person Mark; 16.12.2008
comment
...(продолжение) Я просто подумал, что есть лучший способ сделать это. - person Mark; 16.12.2008
comment
@Dan, хороший момент относительно последовательности, но я подумал, что он пытается создать что-то вроде сброса пароля или чего-то еще, сохранить его и отправить по электронной почте (или что-то в этом роде). @Марк, близко? - person BQ.; 16.12.2008
comment
@BQ, не совсем ... фактические бизнес-требования для этого кода действительно скучны и требуют много объяснений ... - person Mark; 16.12.2008
comment
@BQ: я предполагал (как и вы), что уникальное значение будет использоваться в качестве семени или соли для какого-либо другого бизнес-процесса. Но я понимаю вашу точку зрения, GUID, вероятно, сложнее угадать, если он используется без какого-либо преобразования. - person Dan Vinton; 16.12.2008
comment
@Mark: Если вы даже просто наметите, для чего вам нужно значение, мы можем указать вам либо на GUID, либо на значение последовательности ... - person Dan Vinton; 16.12.2008

«Вам вообще не нужно знать, что это такое, это просто код, который генерирует функция». Тогда он должен быть основан на времени, потому что что-то еще, и нам нужно знать, чтобы дать соответствующий ответ. Не уверен, что на вашей пропускной способности. Вы можете посмотреть DBMS_LOCK.REQUEST как 1a, DBMS_LOCK.SLEEP как 2a и DBMS_LOCK.RELEASE как 2b. Это может гарантировать, что каждая блокировка удерживается в течение одной секунды, так что в любую секунду может произойти только одна вставка.

Если это основано на последовательности, Oracle гарантирует, что вы не получите одну и ту же последовательность дважды

Если это зависит от состояния сеанса/пакета (например, приращение в сеансе), то сеанс может иметь только одну вставку за раз (хотя это может быть многострочная вставка... выбор или даже вставка из нескольких таблиц) .

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

person Gary Myers    schedule 16.12.2008

Одним из решений является использование последовательности Oracle для передачи вашего пользовательского кода, который генерирует уникальную строку. Oracle предоставляет последовательности именно по этой причине, поэтому методы, генерирующие уникальные идентификаторы, являются потокобезопасными. См. здесь документацию по Oracle 9i ( версия, которую я использую).

person darreljnz    schedule 16.12.2008