Сохранение и обновление записей в MySQL через PHP
Запись данных в базу данных с помощью PDO
Наиболее современный и безопасный способ записи данных в базу данных из PHP - использование расширения PDO (PHP Data Objects) с подготовленными запросами. PDO поддерживает множество СУБД и защищает от SQL-инъекций.
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('INSERT INTO users (name, email) VALUES (:name, :email)');
$stmt->execute([':name' => 'Иван', ':email' => 'ivan@example.com']);
echo "Данные добавлены";
Php запись в базу данных (запись данных в базу данных php)
Пояснение: Создаётся подключение, включается режим исключений для обработки ошибок. Подготовленный запрос с именованными плейсхолдерами (:name, :email) затем выполняется с передачей ассоциативного массива. Это исключает возможность инъекций и автоматически экранирует значения.
Возникающие проблемы и их решение:
- Ошибка подключения (неверный хост, логин, пароль). Решение: обернуть создание PDO в блок try-catch и ловить PDOException.
- Дубликат уникального ключа. Решение: использовать INSERT IGNORE или ON DUPLICATE KEY UPDATE в запросе.
- Несоответствие типов данных (например, строка вместо числа). Решение: явно указывать параметры с помощью bindValue и констант PDO::PARAM_*.
Как выполнить запись через объектно-ориентированный mysqli?
$mysqli = new mysqli('localhost', 'user', 'pass', 'test');
$stmt = $mysqli->prepare('INSERT INTO users (name, email) VALUES (?, ?)');
$stmt->bind_param('ss', $name, $email);
$name = 'Петр';
$email = 'petr@example.com';
$stmt->execute();
Цель: Использовать встроенное в PHP расширение MySQL, если PDO недоступен. Подготовленные запросы аналогичны PDO, но требуется ручное указание типов через строку 'ss'.
- Ошибка при неверном порядке или количестве плейсхолдеров. Решение: строгая проверка соответствия bind_param.
- Необходимость проверять $stmt->error после каждого вызова.
Как использовать процедурный стиль mysqli?
$conn = mysqli_connect('localhost', 'user', 'pass', 'test');
$stmt = mysqli_prepare($conn, 'INSERT INTO users (name, email) VALUES (?, ?)');
mysqli_stmt_bind_param($stmt, 'ss', $name, $email);
mysqli_stmt_execute($stmt);
Цель: Для проектов, где принят процедурный стиль кода. Требует тех же мер предосторожности, что и объектный mysqli.
- Меньшая читаемость при большом количестве запросов.
- Забывчивость передачи $conn в каждую функцию.
Как вставить данные, игнорируя ошибки дублирования?
$pdo->exec('INSERT IGNORE INTO users (id, name) VALUES (1, "test")');
Цель: Пропускать вставку, если такой ключ уже существует. Удобно для наполнения тестовых данных.
- INSERT IGNORE подавляет не только дубликаты, но и другие ошибки (например, неверные типы). Решение: использовать ON DUPLICATE KEY UPDATE для более контролируемого поведения.
Как обеспечить атомарность записи с транзакциями?
$pdo->beginTransaction();
try {
$pdo->exec('UPDATE accounts SET balance = balance - 100 WHERE id = 1');
$pdo->exec('UPDATE accounts SET balance = balance + 100 WHERE id = 2');
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
echo "Ошибка: " . $e->getMessage();
}
Цель: Гарантировать, что все изменения будут выполнены или полностью отменены.
- Забывчивость вызова commit() или rollBack() приводит к блокировкам. Решение: всегда использовать try-catch.
- Некоторые СУБД (MyISAM) не поддерживают транзакции. Решение: использовать InnoDB.
Расширенные примеры записи данных
Пакетная вставка нескольких записей в одной транзакции
Код:
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$pdo->beginTransaction();
$stmt = $pdo->prepare('INSERT INTO users (name, email) VALUES (:name, :email)');
$users = [
['name' => 'Anna', 'email' => 'anna@example.com'],
['name' => 'Bob', 'email' => 'bob@example.com'],
['name' => 'Charlie', 'email' => 'charlie@example.com']
];
foreach ($users as $user) {
$stmt->execute($user);
}
$pdo->commit();
echo "Добавлено " . count($users) . " записей.";
Результат:
Добавлено 3 записей.
Транзакция гарантирует, что все три записи будут вставлены атомарно. При ошибке в одной из них произойдёт откат.
Вставка с возвратом последнего ID
$pdo = new PDO('...');
$stmt = $pdo->prepare('INSERT INTO posts (title, body) VALUES (:title, :body)');
$stmt->execute([':title' => 'Новый пост', ':body' => 'Содержимое']);
$postId = $pdo->lastInsertId();
echo "Создан пост с ID: $postId";
Создан пост с ID: 42
Примечание: Метод lastInsertId() возвращает ID, сгенерированный последним INSERT в текущем соединении. Работает только если таблица имеет поле с AUTO_INCREMENT.
Запись с обработкой дубликатов (ON DUPLICATE KEY UPDATE)
$stmt = $pdo->prepare('
INSERT INTO page_views (page_slug, views) VALUES (:slug, 1)
ON DUPLICATE KEY UPDATE views = views + 1
');
$stmt->execute([':slug' => 'home']);
echo "Счётчик обновлён.";
Счётчик обновлён.
Этот запрос либо вставляет новую строку, либо увеличивает существующий счётчик. Поле page_slug должно быть уникальным (PRIMARY KEY или UNIQUE).
Использование именованных плейсхолдеров с явным указанием типов
$stmt = $pdo->prepare('INSERT INTO products (name, price, active) VALUES (:name, :price, :active)');
$stmt->bindValue(':name', 'Книга', PDO::PARAM_STR);
$stmt->bindValue(':price', 15.99, PDO::PARAM_STR);
$stmt->bindValue(':active', 1, PDO::PARAM_INT);
$stmt->execute();
Привязка через bindValue позволяет указать тип параметра, что может быть критично для некоторых СУБД. Позиционные плейсхолдеры (?) менее читаемы, но тоже допустимы.
Вставка значений NULL
$stmt = $pdo->prepare('INSERT INTO users (email, deleted_at) VALUES (?, ?)');
$stmt->execute(['user@example.com', null]);
echo "Пользователь с NULL датой удаления.";
При передаче null в execute PDO автоматически преобразует его в SQL NULL.