Фон: http://jeffkemponoracle.com/2011/03/11/handling-unique-constraint-violations-by-hibernate
Наш стол:
BOND_PAYMENTS (BOND_PAYMENT_ID, BOND_NUMBER, PAYMENT_ID)
Существует ограничение первичного ключа для BOND_PAYMENT_ID и ограничение уникальности для (BOND_NUMBER, PAYMENT_ID).
Приложение использует Hibernate и позволяет пользователю просматривать все платежи, связанные с конкретной Облигацией; и это позволяет им создавать новые ссылки и удалять существующие ссылки. После того, как они внесли все необходимые изменения на странице, они нажимают «Сохранить», и Hibernate делает все возможное, чтобы запустить необходимый SQL в базе данных. По-видимому, Hibernate определяет, какие записи необходимо удалить, какие нужно вставить, и оставляет остальные нетронутыми. К сожалению, сначала он делает INSERT, затем выполняет DELETE.
Если пользователь удаляет ссылку на платеж, затем передумает и повторно вставляет ссылку на тот же платеж, Hibernate с радостью пытается вставить его, а затем удалить. Поскольку эти вставки / удаления выполняются как отдельные операторы SQL, Oracle немедленно проверяет ограничение при первой вставке и выдает ORA-00001, нарушенное уникальное ограничение .
Нам известны только два варианта:
- Сделать ограничение отложенным
- Снять уникальное ограничение
Вариант 2 не очень приятен на вкус, поскольку ограничение обеспечивает превосходную защиту от неприятных ошибок приложения, которые могут позволить сохранить противоречивые данные. Мы пошли с вариантом 1.
ALTER TABLE bond_payments ADD
CONSTRAINT bond_payment_uk UNIQUE (bond_number, payment_id)
DEFERRABLE INITIALLY DEFERRED;
Недостатком является то, что индекс, созданный для контроля этого ограничения, теперь является неуникальным индексом, поэтому может быть несколько менее эффективным для запросов. Мы решили, что это не такой большой ущерб для этого конкретного случая. Другим недостатком (по совету Гэри) является то, что он может страдать от конкретной ошибки Oracle - хотя я считаю, что мы будем защищены (по крайней мере, в основном) от работы приложения.
Есть ли другие варианты, которые мы должны рассмотреть?