При массовой вставке одна строка нарушает ограничение: что произойдёт с остальными строками в транзакционной СУБД?
В обычной транзакционной СУБД ошибка одной строки делает весь оператор массовой вставки неуспешным: строки, уже обработанные этим оператором, откатываются, поэтому частичный результат не сохраняется. Это относится к одному оператору; судьба всей транзакции после ошибки зависит от СУБД и её режима.
Если email объявлен уникальным, оператор завершится ошибкой из-за второй строки, и вставка первой строки этим оператором также будет отменена.
Такое поведение связано с требованиями атомарности транзакций и поддержанием ограничений целостности. База данных не должна оставаться в состоянии, где часть логически единой операции применена, а часть отклонена из-за нарушения правила.
Транзакции появились как механизм выполнения связанных изменений по принципу «всё или ничего». Это особенно важно для массовых операций, где приложение не должно самостоятельно угадывать, какие строки уже были записаны до возникновения ошибки.
Массовая загрузка может содержать тысячи строк, а ошибка может возникнуть из-за дубликата ключа, нарушения внешнего ключа, ограничения CHECK или недопустимого NULL. Если сохранить успешно обработанные строки, результат будет зависеть от позиции ошибочной строки и порядка обработки.
Нельзя автоматически считать, что ошибка одного оператора откатывает все предыдущие изменения транзакции. Например, одни СУБД после ошибки переводят всю транзакцию в состояние, требующее отката, а другие позволяют продолжить работу. Это отдельный вопрос от атомарности самого оператора.
Атомарность означает, что оператор имеет только два результата: все его изменения применены либо ни одно из них не считается применённым. При нарушении немедленно проверяемого ограничения СУБД отменяет изменения, выполненные этим оператором.
Если ограничение отложенное, ошибка может быть обнаружена не во время вставки, а при проверке в конце транзакции. Итог тот же: транзакция не сможет успешно зафиксировать нарушающее ограничение состояние.
Чтобы сохранить корректные строки и отдельно обработать ошибочные, применяют один из подходов:
Последний вариант меняет семантику операции: строка может быть не отклонена с ошибкой, а пропущена или преобразована. Поэтому такое поведение должно быть частью бизнес-решения, а не случайным способом скрыть проблемы данных.
Точка сохранения позволяет откатить часть действий внутри более крупной транзакции, но это не превращает один многострочный оператор в набор независимо успешных вставок. Для такого результата обычно нужны отдельные операторы, промежуточная таблица или специальный режим загрузки.
Сервис получает файл со 100 000 платежей. В файле есть один повторный идентификатор платежа, и прямая вставка всей выборки завершается ошибкой. Вариант с построчной вставкой сохраняет корректные записи, но создаёт много обращений к базе и усложняет повторную обработку.
Вариант с безусловным пропуском конфликтов быстрее, однако может скрыть не только ожидаемые дубликаты, но и дефект источника. Оптимальным решением будет загрузка в промежуточную таблицу, отчёт о дубликатах и отдельная транзакция переноса валидных платежей в рабочую таблицу.
Такой подход сохраняет атомарность публикации данных, позволяет повторно обработать исправленный файл и даёт наблюдаемую причину отказа. В рабочей таблице не появляется частично неизвестный набор платежей.
Нет, это не следует непосредственно из атомарности оператора. Оператор откатывает свои изменения, но конкретная СУБД может оставить транзакцию пригодной для продолжения либо перевести её в ошибочное состояние до явного отката. В PostgreSQL ошибка обычно делает текущую транзакцию непригодной для обычных дальнейших операторов без отката или отката к точке сохранения.
Да, если разделить работу на несколько операторов и после ошибки откатить только последний участок к точке сохранения. Нельзя рассчитывать, что точка сохранения позволит выборочно оставить строки, успешно обработанные внутри одного неуспешного многострочного оператора: атомарность этого оператора сохраняется.
Нет, если явно задана политика обработки конфликтов или используется специальный режим загрузки. Например, конструкция с пропуском конфликта может принять уникальные строки и проигнорировать дубликаты, а конструкция обновления при конфликте изменит существующую запись. Это уже другая семантика, которую нужно оценивать с точки зрения потери данных, аудита и повторяемости загрузки.