Работа с базами данных SQL в PHP: от подключения до транзакций
Подключение и выполнение запросов к SQL из PHP
Какое расширение PHP является наиболее эффективным и современным для работы с SQL?
Наиболее эффективным решением является использование расширения PDO (PHP Data Objects). PDO обеспечивает абстракцию доступа к базе данных, единый интерфейс для разных СУБД (MySQL, PostgreSQL, SQLite и др.) и поддержку подготовленных запросов (prepared statements), что защищает от SQL-инъекций. Пример подключения:
$dsn = 'mysql:host=localhost;dbname=mydb;charset=utf8mb4';
$user = 'root';
$password = '';
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
try {
$pdo = new PDO($dsn, $user, $password, $options);
} catch (PDOException $e) {
die('Ошибка подключения: ' . $e->getMessage());
}
Php class sql (класс для работы с sql в php)
В этом примере задан DSN (Data Source Name) для MySQL, указаны имя пользователя и пароль, а также настройки: генерация исключений при ошибках, режим выборки по умолчанию (ассоциативный массив) и отключение эмуляции подготовленных запросов для использования реальной многоразовой подготовки.
После успешного подключения можно выполнять запросы. Пример выборки данных:
$stmt = $pdo->query('SELECT id, name FROM users');
while ($row = $stmt->fetch()) {
echo $row['name'] . '\n';
}
Php sql insert (insert в php)
Типичная ошибка: неверные параметры подключения
Ошибка SQLSTATE[HY000] [1045] Access denied означает неверный логин или пароль. Решение: проверьте учётные данные и права доступа.
Ошибка could not find driver возникает, если в PHP не установлен драйвер PDO для используемой СУБД (например, pdo_mysql). Установите расширение через менеджер пакетов вашей ОС или в php.ini.
Как использовать расширение mysqli (MySQL Improved) в процедурном стиле?
Расширение mysqli предназначено только для MySQL и поддерживает как процедурный, так и объектно-ориентированный стиль. Пример процедурного подключения:
$link = mysqli_connect('localhost', 'root', '', 'mydb');
if (!$link) {
die('Ошибка подключения: ' . mysqli_connect_error());
}
mysqli_set_charset($link, 'utf8mb4');
$result = mysqli_query($link, 'SELECT id, name FROM users');
while ($row = mysqli_fetch_assoc($result)) {
echo $row['name'] . '\n';
}
mysqli_close($link);
Php ms sql (работа с ms sql в php)
Цель использования mysqli - работа исключительно с MySQL, особенно в проектах, где не требуется смена СУБД. Встроенная поддержка подготовленных запросов также присутствует, но синтаксис более громоздкий.
Проблема: смешивание функций mysql_* и mysqli_*
Использование устаревшего расширения mysql (удалено в PHP 7) приведёт к фатальным ошибкам. Мигрируйте на mysqli или PDO.
Как выполнять запросы с параметрами, защищёнными от SQL-инъекций, в PDO?
Подготовленные запросы (prepared statements) - основной способ безопасной передачи параметров. Пример:
$sql = 'SELECT name, email FROM users WHERE id = :id';
$stmt = $pdo->prepare($sql);
$stmt->execute([':id' => 42]);
$user = $stmt->fetch();
переменную sql php (использование переменных в sql-запросах php)
Здесь плейсхолдер :id заменяется на значение 42, причём экранирование выполняется автоматически. Альтернативно можно использовать позиционные плейсхолдеры ?.
Ошибка: использование разных типов плейсхолдеров в одном запросе
Смешивание именованных (:name) и позиционных (?) плейсхолдеров в одном запросе вызовет ошибку. Выберите один стиль.
Как обрабатывать ошибки выполнения запросов?
В PDO удобно использовать режим исключений (ERRMODE_EXCEPTION). Пример с try-catch:
try {
$pdo->exec('INSERT INTO users (name) VALUES ("Иван")');
echo 'Добавлено успешно';
} catch (PDOException $e) {
echo 'Ошибка: ' . $e->getMessage();
}
В mysqli можно проверять mysqli_errno() или mysqli_error().
Забытый коммит транзакции
При использовании транзакций без автоматического коммита все изменения будут откачены при завершении скрипта, если не вызван commit(). Всегда проверяйте успешность и вызывайте rollback() в случае ошибки.
Какие цели и случаи использования каждого варианта?
PDO - универсальное решение для проектов, где требуется поддержка нескольких СУБД или переносимость кода. Идеально для современных приложений, фреймворков (Laravel, Symfony). mysqli - выбор для быстрой интеграции с MySQL без дополнительных абстракций, если проект не планирует менять СУБД. Устаревшее mysql не рассматривается из-за полной небезопасности и удаления из PHP.
Расширенные примеры работы с SQL в PHP
Пример транзакции с PDO
Транзакции позволяют выполнить несколько запросов как единое целое. Если один запрос ошибочен, все изменения откатываются.
try {
$pdo->beginTransaction();
$pdo->exec('UPDATE accounts SET balance = balance - 100 WHERE id = 1');
$pdo->exec('UPDATE accounts SET balance = balance + 100 WHERE id = 2');
$pdo->commit();
echo 'Перевод успешен';
} catch (PDOException $e) {
$pdo->rollBack();
echo 'Ошибка: ' . $e->getMessage();
}
Результат: При успешном выполнении обоих UPDATE данные изменятся. При ошибке (например, отрицательный баланс) изменения откатятся.
(при успехе) Перевод успешен (при ошибке) Ошибка: ...
Массовая вставка с подготовленным запросом
Для вставки нескольких записей эффективно использовать один подготовленный запрос, повторяя его в цикле с разными данными.
$pdo->beginTransaction();
$sql = 'INSERT INTO products (name, price) VALUES (:name, :price)';
$stmt = $pdo->prepare($sql);
$products = [
['name' => 'Товар1', 'price' => 100],
['name' => 'Товар2', 'price' => 200],
['name' => 'Товар3', 'price' => 150],
];
foreach ($products as $product) {
$stmt->execute($product);
}
$pdo->commit();
echo 'Вставлено ' . count($products) . ' записей';
Результат - все три товара добавлены в таблицу за одну транзакцию.
Вставлено 3 записи
Выборка данных в виде объектов
PDO может извлекать строки как объекты заданного класса.
class User {
public $id;
public $name;
public $email;
}
$stmt = $pdo->query('SELECT id, name, email FROM users');
$users = $stmt->fetchAll(PDO::FETCH_CLASS, 'User');
foreach ($users as $user) {
echo $user->name . ' (' . $user->email . ')' . PHP_EOL;
}
Результат - каждая строка становится объектом User с публичными свойствами, названия которых совпадают с именами столбцов.
Обработка ошибок в mysqli с использованием исключений
В mysqli можно включить режим исключений, установив MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT.
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$link = mysqli_connect('localhost', 'root', '', 'mydb');
$result = mysqli_query($link, 'SELECT * FROM nonexistent');
При ошибке (например, несуществующая таблица) скрипт выбросит исключение mysqli_sql_exception. Без этого режима ошибки молча возвращают false, и их нужно проверять вручную.
Получение количества затронутых строк
После UPDATE, DELETE или INSERT можно получить количество изменённых строк через rowCount() в PDO или mysqli_affected_rows() в mysqli.
$stmt = $pdo->exec('DELETE FROM logs WHERE date < "2020-01-01"');
echo 'Удалено строк: ' . $stmt; // для exec возвращается количество
// или
$stmt = $pdo->prepare('DELETE FROM logs WHERE date < :date');
$stmt->execute([':date' => '2020-01-01']);
echo 'Удалено строк: ' . $stmt->rowCount();