Если вы получаете это сообщение во время сохранения или компиляции сборки, просто закройте все файлы, а затем откройте любой файл для компиляции и сохранения.
Для меня причина в том, что я переименовал файл, и старый файл все еще был открыт.
Как вы заметили, будет сложно ответить на ваши бизнес-требования с помощью триггеров. Причина в том, что Oracle может обновлять / вставлять таблицы с несколькими потоками одновременно для одного запроса (параллельный DML). Это означает, что ваш сеанс не может запрашивать таблицу, которую он обновляет, пока происходит обновление.
Если вы действительно хотите сделать это с помощью триггеров, вам придется следовать вид логики, показанный в этом статья Тома Ките . Как вы видите, это не что-то простое.
Существует еще один, более простой, более элегантный, более простой в обслуживании метод: использование процедур. Отменить право на обновление / вставить пользователю (пользователям) приложения и написать набор процедур, которые позволяют приложению обновлять столбцы состояния.
Эти процедуры будут содержать блокировку родительской строки ( для предотвращения нескольких сеансов для изменения одного и того же набора строк) и будет применять вашу бизнес-логику эффективным, понятным и легко поддерживаемым способом.
Я видел некоторые мнения о том, что ошибка мутирующей таблицы указывает на недостатки в логике приложения - это правда и как я могу изменить свою логику, чтобы предотвратить эту ошибку?
blockquote>Я не знаю, где вы это видели, но я знаю, что много раз высказывал это мнение.
Почему я думаю, что мутирующие таблицы обычно указывают на недостаток в модели данных? Потому что «требование», которое управляет кодом, которое швыряет ORA-4091, часто связано с плохим дизайном, особенно с недостаточной нормализацией.
Этот сценарий является классическим примером этого. Вы получаете ORA-04091, потому что вы выбираете из
TableC
, когда вы вставляете или обновляете его. Но почему вы выбираете изTableC
? Потому что вам «нужно» обновить столбец родителя,TableB
. Но эта колонка - избыточная информация. В полностью нормированной модели данных этот столбец не будет существовать.Денормализацию часто рекламируют как механизм повышения производительности запросов. К сожалению, сторонники денормализации замалчивают свою стоимость, которая выплачивается в валюте чрезмерной сложности при вставке, обновлении и удалении.
Итак, как вы можете изменить свою логику? Простым ответом является удаление столбцов и не беспокоить сохранение наименьшего состояния по идентификатору родителя. Вместо этого выполняйте запрос
MIN()
всякий раз, когда вам нужна эта информация. Если вам это нужно часто, и было бы дорого выполнить запрос, тогда вы создадите материализованные представления, которые хранят данные (обязательно используйтеENABLE QUERY REWRITE
)
Ведение подобных вещей - великий соблазн, и если вы будете следовать рекомендациям в статье Тома Ките, на которые ссылаются другие, это возможно. Однако только потому, что что-то можно сделать, это не значит, что это нужно сделать. Я настоятельно рекомендую вам реализовать что-то подобное в виде хранимой процедуры / функции / пакета. Сложная логика такого рода не должна выполняться с использованием триггеров, несмотря на очевидные соблазны, поскольку это значительно повышает сложность системы без соответствующего увеличения полезности.
Удачи.
Мне нужно работать над кодом, как это иногда, и это не радость.Не используйте автономные транзакции, или вы получите очень интересные результаты .
Чтобы избежать проблемы с изменяющимися таблицами, вы можете сделать следующее:
В ПОСЛЕ ВСТАВКИ ИЛИ ОБНОВЛЕНИЯ ИЛИ УДАЛИТЬ ДЛЯ КАЖДОГО триггера ROW найдите идентификатор родителя и сохраните его в коллекции PL / SQL (внутри ПАКЕТА). Затем, в ПОСЛЕ ВСТАВКИ ИЛИ ОБНОВЛЕНИЯ ИЛИ УДАЛИТЬ ТРИГГЕР (уровень инструкции, без части «для каждой строки»), прочитайте родительские идентификаторы из коллекции PL / SQL и соответствующим образом обновите родительскую таблицу.
В качестве примера того, почему ваша логика потерпит неудачу, возьмите сценарий, в котором PARENT A имеет запись 1 с рекордами CHILD 1A и 1B. STATE 1A - 10 и 1B - 15, поэтому вы хотите, чтобы ваш родитель был равен 10.
Теперь кто-то обновляет состояние 1A до 20, а в то же время кто-то удаляет 1B. Поскольку удаление 1B не завершено, обновление транзакции 1A по-прежнему будет видеть 1B и будет хотеть установить состояние родителя на 15, в то время как транзакция, удаляющая 1B, увидит старое незафиксированное значение 1A и будет хотеть, чтобы родительское состояние было 10.
Если вы де-нормализуете это, вы должны быть очень осторожны с блокировкой, чтобы, прежде чем вставлять / обновлять / удалять любые дочерние записи, родительская запись заблокирована, выполнить ваши изменения, выбрать все дочерние записи, обновить родительский элемент, а затем зафиксировать блокировку. Хотя это можно сделать с помощью триггеров, вам лучше всего сохранить хранимую процедуру.
Вы не должны использовать триггеры для сложной бизнес-логики. Переместите его в сохраненный 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
Можете ли вы реорганизовать решение, чтобы включить представления для выполнения вычисления?
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»: это может быть хорошо - это зависит от ваших требований.
Я предполагаю, что еще один вариант - создать некоторые функции для вычисления, но лично я бы выбрал подход к просмотру (при прочих равных условиях).
Вы можете использовать оба триггера и ограничения целостности для определения и обеспечения соблюдения любого типа правила целостности. Однако корпорация Oracle настоятельно рекомендует использовать триггеры для ограничения ввода данных только в следующих ситуациях:
Обеспечить ссылочную целостность, когда дочерние и родительские таблицы находятся на разных узлах распределенной базы данных. Для обеспечения соблюдения сложных бизнес-правил, определяемый с использованием ограничений целостности Когда требуемое правило ссылочной целостности не может быть принудительно применено с использованием следующих ограничений целостности:
blockquote>
- NOT NULL, UNIQUE
- ПЕРВИЧНЫЙ КЛЮЧ
- FOREIGN KEY
- CHECK
- DELETE CASCADE
- DELETE SET NULL