#Симптом и границы применимости
SQLite контролирует внешние ключи отдельно для каждого нового подключения, если PRAGMA foreign_keys включена до начала транзакции. Настройка одного sqlite3-клиента не распространяется на все соединения PHP/Python и не меняет уже начатую транзакцию.
#Как отличить возможные причины
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Новая сессия сбрасывает настройкуPRAGMA foreign_keys — настройка соединения, а не постоянное свойство файла. | sqlite3 показывает ON, PHP — OFF | Установить при создании соединения |
| Команда внутри транзакцииИзменение PRAGMA foreign_keys во время BEGIN не действует. | Внутри транзакции остается 0 | Перенести до BEGIN |
| Есть старые нарушенные ссылкиВключение контроля не исправляет исторические сиротские строки. | PRAGMA foreign_key_check возвращает строки | Согласовать исправление данных |
#Пошаговая диагностика и безопасное исправление
- 1. Уточните, где создаётся соединениеНайдите файл PHP или Python, в котором открывается SQLite, и все места повторного открытия базы, включая фоновые задачи. Не считайте установку PRAGMA из консоли постоянной настройкой сервера.
- 2. Проверьте значение на новом соединенииВ терминале откройте sqlite3 именно для нужного файла тестовой базы. Проверьте PRAGMA foreign_keys сразу после открытия; 0 означает, что на данном соединении контроль не включён.Linux · Терминал (Bash)КомандаТерминал с SQLite CLI; чтение. ./test.db — только существующая копия базы, не открывайте неизвестный путь (он может создать пустой файл).
sqlite3 ./test.db "PRAGMA foreign_keys;"
- 3. Проверяйте ограничения на тестовой копииЗапустите foreign_key_check: он находит уже существующие нарушения, но не исправляет их. Результат без строк — ожидаемое состояние здоровой базы с проверяемыми ограничениями.
- В sqlite3 внутри тестовой базы; чтение, возможна нагрузка на большую базуSQLКомандаВ sqlite3 внутри тестовой базы; чтение, возможна нагрузка на большую базу.
PRAGMA foreign_key_check;
- 4. Включите проверку до первой транзакцииВ коде при каждом новом подключении выполняйте PRAGMA foreign_keys=ON до BEGIN и перед любыми подготовленными запросами, зависящими от настройки. Затем сразу запросите текущее значение и убедитесь, что оно 1.
- 5. Добавьте установку в PHP PDO на тестеЕсли сайт использует PDO_SQLITE, выполните PRAGMA после new PDO и до начала транзакции. Пример не подменяет реальный путь и не должен открывать производственную базу из тестового сценария.
- Дополнительная команда по темеPHPКомандаФрагмент PHP только для тестового файла; ожидается int(1) либо строка «1» в зависимости от драйвера.
$db = new PDO('sqlite:/absolute/path/to/test.db');$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);$db->exec('PRAGMA foreign_keys = ON');var_dump($db->query('PRAGMA foreign_keys')->fetchColumn());
- 6. Отдельно испытайте соединения из пулаЗапустите два независимых подключения и проверьте PRAGMA foreign_keys в каждом, затем проведите безопасный INSERT с некорректной ссылкой в откатываемой тестовой транзакции. Ожидается отказ FOREIGN KEY constraint failed.
- 7. Разберите ошибки старых данных до выпускаЕсли foreign_key_check выявил сироты, составьте список и согласуйте восстановление корректных родительских записей или удаление по бизнес-правилам. Не отключайте проверку ради успешного завершения миграции.
- 8. Проверьте поведение после перезапуска процессаПерезапустите только тестовое приложение, создайте свежее соединение и убедитесь, что PRAGMA снова равна 1. Автотест должен проверять это каждый раз при развёртывании.
#Как проверить, что проблема устранена
Каждое новое тестовое подключение показывает PRAGMA foreign_keys = 1; допустимые ссылки проходят, недопустимые завершаются ошибкой целостности.
#Если исправление не помогло
Если PRAGMA остаётся 0, проверьте, не выполняется ли она внутри BEGIN и не открывает ли код другую базу. На очень старых сборках SQLite поддержка FK может быть отключена при компиляции.