В одной транзакции сначала создают дочернюю строку, а затем родительскую: от чего зависит, допустим ли такой порядок?
Порядок допустим только при отложенной проверке внешнего ключа или если ограничение проверяется после появления родительской строки. При немедленной проверке вставка дочерней строки завершится ошибкой сразу: сама транзакция не откладывает проверку ограничений автоматически.
Внешние ключи нужны для поддержания ссылочной целостности: каждая ссылка из дочерней таблицы должна указывать на существующую родительскую строку. Транзакции обеспечивают атомарность набора операций, но не отменяют проверку целостности на отдельных этапах.
Для сложных изменений, циклических зависимостей и пакетной загрузки появился механизм отложенных ограничений. Он позволяет временно иметь незавершённое состояние внутри транзакции, но требует корректного состояния к моменту проверки.
При немедленном ограничении вставка дочерней строки проверяется в момент выполнения операции. Если родитель ещё не существует, операция отклоняется, даже если следующая команда той же транзакции должна была создать родителя.
При отложенной проверке промежуточное состояние допускается, но ошибка обнаружится при фиксации транзакции, если родитель так и не был создан. Поэтому успешное выполнение отдельных операций не гарантирует успешный COMMIT.
У внешнего ключа важны два свойства: возможность откладывать проверку и начальный режим проверки. Немедленное ограничение проверяется после операции, а отложенное — в конце транзакции либо в момент, явно заданный правилами конкретной СУБД.
Концептуальный пример стандартного SQL:
Здесь первая вставка временно нарушает ссылочную целостность, но к моменту фиксации родитель существует. Если ограничение объявлено как NOT DEFERRABLE или работает в немедленном режиме, первая вставка будет отклонена.
Поддержка отложенных ограничений и способы управления их режимом зависят от СУБД, поэтому переносимость такого решения ниже, чем у перестановки операций. Если порядок можно изменить без потери смысла, обычно безопаснее сначала создать родительскую строку, затем дочернюю.
Отложенная проверка не означает отключение внешнего ключа. Она лишь меняет момент проверки; при нарушении на границе транзакции фиксация должна завершиться ошибкой.
При импорте данных приложение получает сначала дочерние записи, а сведения о родителях — позже. Рассматривались два варианта: временно отключать внешний ключ или объявить его отложенным. Отключение ускоряет загрузку, но создаёт риск незаметно сохранить повреждённые ссылки и требует отдельной проверки.
Был выбран отложенный внешний ключ, поскольку все записи загружались в одной транзакции и к её завершению родители гарантированно появлялись. Результатом стала сохранённая ссылочная целостность без зависимости от порядка входных записей; при этом команда добавила обработку ошибки фиксации транзакции.
Если же порядок операций легко контролируется, предпочтительнее сначала вставлять родителей. Такой вариант проще, лучше поддерживается разными СУБД и обнаруживает ошибку ближе к месту её возникновения.
Нет. Транзакция гарантирует атомарность и изоляцию в соответствии с выбранным уровнем, но не меняет режим проверки ограничений. Внешний ключ может оставаться немедленным и отклонить дочернюю вставку до выполнения следующей операции.
Фиксация транзакции завершится ошибкой, а транзакция не станет успешно сохранённой. Приложение должно обработать эту ошибку и обычно выполнить откат либо исправить данные до повторной попытки фиксации.
Отложенное ограничение продолжает действовать и проверяется в установленный момент, поэтому некорректные данные не могут успешно попасть в базу. Отключённое ограничение не обеспечивает такой гарантии: ошибки можно сохранить, если отдельная проверка не будет выполнена вручную.