Таблица мутирует триггер / функция, возможно, не видит его Oracle [duplicate]

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

Для меня причина в том, что я переименовал файл, и старый файл все еще был открыт.

6
задан APC 17 November 2011 в 15:06
поделиться

8 ответов

Как вы заметили, будет сложно ответить на ваши бизнес-требования с помощью триггеров. Причина в том, что Oracle может обновлять / вставлять таблицы с несколькими потоками одновременно для одного запроса (параллельный DML). Это означает, что ваш сеанс не может запрашивать таблицу, которую он обновляет, пока происходит обновление.

Если вы действительно хотите сделать это с помощью триггеров, вам придется следовать вид логики, показанный в этом статья Тома Ките . Как вы видите, это не что-то простое.

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

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

12
ответ дан Vincent Malgrat 27 August 2018 в 08:09
поделиться

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

Я не знаю, где вы это видели, но я знаю, что много раз высказывал это мнение.

Почему я думаю, что мутирующие таблицы обычно указывают на недостаток в модели данных? Потому что «требование», которое управляет кодом, которое швыряет ORA-4091, часто связано с плохим дизайном, особенно с недостаточной нормализацией.

Этот сценарий является классическим примером этого. Вы получаете ORA-04091, потому что вы выбираете из TableC, когда вы вставляете или обновляете его. Но почему вы выбираете из TableC? Потому что вам «нужно» обновить столбец родителя, TableB. Но эта колонка - избыточная информация. В полностью нормированной модели данных этот столбец не будет существовать.

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

Итак, как вы можете изменить свою логику? Простым ответом является удаление столбцов и не беспокоить сохранение наименьшего состояния по идентификатору родителя. Вместо этого выполняйте запрос MIN() всякий раз, когда вам нужна эта информация. Если вам это нужно часто, и было бы дорого выполнить запрос, тогда вы создадите материализованные представления, которые хранят данные (обязательно используйте ENABLE QUERY REWRITE)

3
ответ дан APC 27 August 2018 в 08:09
поделиться

Ведение подобных вещей - великий соблазн, и если вы будете следовать рекомендациям в статье Тома Ките, на которые ссылаются другие, это возможно. Однако только потому, что что-то можно сделать, это не значит, что это нужно сделать. Я настоятельно рекомендую вам реализовать что-то подобное в виде хранимой процедуры / функции / пакета. Сложная логика такого рода не должна выполняться с использованием триггеров, несмотря на очевидные соблазны, поскольку это значительно повышает сложность системы без соответствующего увеличения полезности.

Удачи.

Мне нужно работать над кодом, как это иногда, и это не радость.
1
ответ дан Bob Jarvis 27 August 2018 в 08:09
поделиться

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

Чтобы избежать проблемы с изменяющимися таблицами, вы можете сделать следующее:

В ПОСЛЕ ВСТАВКИ ИЛИ ОБНОВЛЕНИЯ ИЛИ УДАЛИТЬ ДЛЯ КАЖДОГО триггера ROW найдите идентификатор родителя и сохраните его в коллекции PL / SQL (внутри ПАКЕТА). Затем, в ПОСЛЕ ВСТАВКИ ИЛИ ОБНОВЛЕНИЯ ИЛИ УДАЛИТЬ ТРИГГЕР (уровень инструкции, без части «для каждой строки»), прочитайте родительские идентификаторы из коллекции PL / SQL и соответствующим образом обновите родительскую таблицу.

1
ответ дан Erich Kitzmueller 27 August 2018 в 08:09
поделиться

В качестве примера того, почему ваша логика потерпит неудачу, возьмите сценарий, в котором PARENT A имеет запись 1 с рекордами CHILD 1A и 1B. STATE 1A - 10 и 1B - 15, поэтому вы хотите, чтобы ваш родитель был равен 10.

Теперь кто-то обновляет состояние 1A до 20, а в то же время кто-то удаляет 1B. Поскольку удаление 1B не завершено, обновление транзакции 1A по-прежнему будет видеть 1B и будет хотеть установить состояние родителя на 15, в то время как транзакция, удаляющая 1B, увидит старое незафиксированное значение 1A и будет хотеть, чтобы родительское состояние было 10.

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

2
ответ дан Gary Myers 27 August 2018 в 08:09
поделиться

Вы не должны использовать триггеры для сложной бизнес-логики. Переместите его в сохраненный proc (пакет PL / SQL) или код клиента. Приложения с множеством триггеров становятся неприступными, потому что вы скоро потеряете чувство «последовательности действий».

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

Чтение: http://www.oracle.com/technetwork/issue-archive/2008/08-sep/o58asktom-101055.html

Здесь вы можете прочитать, как решить проблему, если вы хотите использовать триггеры без использования автономных транзакций: http://www.procaseconsulting.com/learning/papers/200004-mutating-table.pdf

5
ответ дан juanitogan 27 August 2018 в 08:09
поделиться

Можете ли вы реорганизовать решение, чтобы включить представления для выполнения вычисления?

CREATE VIEW a_view AS
SELECT a.Id, min(b.State) State FROM tableA,tableB
WHERE a.Id=b.tableAId
GROUP BY a.Id;

Я согласен с тем, что сохраненные procs (как предлагается здесь в других сообщениях) также являются хорошим кандидатом - но обратите внимание, что представление будет автоматически обновляться, в то время как я полагаю, вам придется запланировать запуск хранимых-procs, чтобы сохранить данные «in-sync»: это может быть хорошо - это зависит от ваших требований.

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

3
ответ дан monojohnny 27 August 2018 в 08:09
поделиться

Вы можете использовать оба триггера и ограничения целостности для определения и обеспечения соблюдения любого типа правила целостности. Однако корпорация Oracle настоятельно рекомендует использовать триггеры для ограничения ввода данных только в следующих ситуациях:

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

  • NOT NULL, UNIQUE
  • ПЕРВИЧНЫЙ КЛЮЧ
  • FOREIGN KEY
  • CHECK
  • DELETE CASCADE
  • DELETE SET NULL

источник: база данных Oracle9i Понятия

2
ответ дан R van Rijn 27 August 2018 в 08:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: