Основы работы с базами данных

Введение

В Laravel можно чрезвычайно просто взаимодействовать с БД на различных "движках", будь то сырой SQL, гибкий построитель запросов или Eloquent ORM. На данный момент Laravel поддерживает четыре системы баз данных:

  • MySQL
  • Postgres
  • SQLite
  • SQL Server

Настройка

Настройка базы данных для вашего приложения хранится в config/database.php. Здесь вы можете указать все используемые вами соединения к БД, а также задать соединение по умолчанию. Примеры настройки большинства поддерживаемых систем БД находятся в этом же файле.

По умолчанию образец настройки среды Laravel уже готов к использованию с Laravel Homestead — удобной виртуальной машиной для Laravel-разработки на вашей локальной машине. Разумеется, вы можете изменить эти настройки для работы с вашей локальной БД.

Настройка SQLite

После создания новой базы данных SQLite при помощи команды touch database/database.sqlite, вы можете легко настроить переменные вашей среды для этой новой базы данных, используя её абсолютный путь:

DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database.sqlite

Настройка SQL Server

Laravel изначально поддерживает работу с SQL Server; однако, потребуется добавить настройку подключения к БД в конфиге config/database.php:

'sqlsrv' => [
    'driver' => 'sqlsrv',
    'host' => env('DB_HOST', 'localhost'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'charset' => 'utf8',
    'prefix' => '',
],

Соединения для чтения и записи

Иногда вам может понадобиться использовать разные подключения к базе данных: одно для запросов SELECT, а другое для запросов INSERT, UPDATE и DELETE. это делается очень просто, и всегда будет использоваться соответствующее соединение, неважно используете ли вы сырые запросы, построитель запросов или Eloquent ORM.

Чтобы увидеть, как должны быть настроены соединения чтения/записи, давайте взглянем на этот пример:

'mysql' => [
    'read' => [
        'host' => '192.168.1.1',
    ],
    'write' => [
        'host' => '196.168.1.2'
    ],
    'driver'    => 'mysql',
    'database'  => 'database',
    'username'  => 'root',
    'password'  => '',
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix'    => '',
],

Обратите внимание, что в массив настроек были добавлены два элемента: read и write. Оба элемента представляют собой массив с одним элементом: host. Остальные параметры БД для подключений чтения/записи будут заимствованы из основного массива mysql.

Вам стоит размещать элементы в массивах read и write aтолько если вы хотите переопределить их значения из основного массива. Таким образом, в этом случае, 192.168.1.1 будет использоваться как хост для подключения "чтения", а 192.168.1.2 - для подключения "записи". Учётные данные для БД, префикс, набор символов, и все другие параметры основного массива mysql будут использованы для обоих подключений.

Использование нескольких соединений с БД

При использовании нескольких соединений с БД вы можете получить доступ к каждому из них через метод connection фасада DB. Передаваемое в этот метод имя name должно соответствовать одному из перечисленных в файле config/database.php:

$users = DB::connection('foo')->select(...);

Вы также можете получить низкоуровневый объект PDO для этого подключения методом getPdo на экземпляре подключения:

$pdo = DB::connection()->getPdo();

Выполнение сырых SQL-запросов

После того как вы настроили соединение с базой данных, вы можете выполнять запросы, используя фасад DB. Этот фасад имеет методы для каждого типа запроса: select, update, insert, delete и statement.

Выполнение запроса Select

Чтобы выполнить базовый запрос, можно использовать метод select фасада DB:

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * Показать список всех пользователей приложения.
     *
     * @return Response
     */
    public function index()
    {
        $users = DB::select('select * from users where active = ?', [1]);

        return view('user.index', ['users' => $users]);
    }
}

Первый аргумент метода select — сырой SQL-запрос, второй — любые связки параметров для прикрепления к запросу. Обычно это значения ограничений условия where. Привязка параметров обеспечивает защиту от SQL-внедрений.

Метод select всегда возвращает массив результатов. Каждый результат в массиве будет объектом PHP stdClass, что позволяет вам обращаться к значениям результатов:

foreach ($users as $user) {
    echo $user->name;
}

Использование привязки имён

Вместо использования знака вопроса ? для обозначения привязки параметров, вы можете выполнить запрос, используя привязку по имени:

$results = DB::select('select * from users where id = :id', ['id' => 1]);

Выполнение запроса Insert

Чтобы выполнить запрос insert, можно использовать метод insert фасада DB. Как и select, данный метод принимает сырой SQL-запрос первым аргументом, а вторым — привязкиt:

DB::insert('insert into users (id, name) values (?, ?)', [1, 'Dayle']);

Выполнение запроса Update

Для обновления существующих записей в БД используется метод update, который возвращает количество изменённых записей:

$affected = DB::update('update users set votes = 100 where name = ?', ['John']);

Выполнение запроса Delete

Для удаления записей из БД используется метод delete, который возвращает количество изменённых записей:

$deleted = DB::delete('delete from users');

Выполнение запроса общего типа

Некоторые запросы к БД не возвращают никаких значений. Для операций такого типа можно использовать метод statement фасада DB:

DB::statement('drop table users');

Прослушивание событий запросов

Если вы хотите получать каждый выполненный вашим приложением SQL-запрос, используйте метод listen. Этот метод полезен для логгирования запросов и отладки. Вы можете зарегистрировать свой слушатель запросов в сервис-провайдере:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Загрузка всех сервисов приложения.
     *
     * @return void
     */
    public function boot()
    {
        DB::listen(function ($query) {
            // $query->sql
            // $query->bindings
            // $query->time
        });
    }

    /**
     * Регистрация сервис-провайдера.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Транзакции БД

Для выполнения набора запросов внутри одной транзакции вы можете использовать метод transaction фасада DB. Если в функции-замыкании произойдёт исключение, транзакция автоматически откатится. А если функция выполнится успешно, транзакция автоматически применится к БД:

DB::transaction(function () {
    DB::table('users')->update(['votes' => 1]);

    DB::table('posts')->delete();
});

Обработка взаимных блокировок

Метод transaction принимает второй необязательный аргумент, с помощью которого задаётся число повторных попыток транзакции при возникновении взаимной блокировки. После истечения этих попыток будет выброшено исключение:

DB::transaction(function () {
    DB::table('users')->update(['votes' => 1]);

    DB::table('posts')->delete();
}, 5);

Ручное использование транзакций

Если вы хотите запустить транзакцию вручную и иметь полный контроль над её откатом и применением, используйте метод beginTransaction фасада DB:

DB::beginTransaction();

Вы можете откатить транзакцию методом rollBack:

DB::rollBack();

Наконец, вы можете применить транзакцию методом commit:

DB::commit();

{tip} Методы фасада DB для транзакций также контролируют транзакции построителя запросов и Eloquent ORM.