Laravel 5.5
Начало работы с базой данных
Введение
В Laravel работа с базами данных предельно проста.
Вы можете использовать:
- Eloquent ORM
- построитель запросов (query builder)
- примитивы для работы с SQL-кодом напрямую.
На данный момент Laravel поддерживает четыре СУБД:
- MySQL
- PosgreSQL
- SQLite
- SQL Server
Настройки
Настройки находятся в файле config/database.php . Вы можете определить несколько подключений к базам данных, указав какое из них использовать по умолчанию. В файле уже приведены наиболее популярные варианты подключений.
По умолчанию приложение настроено на работу с Laravel Homestead, это виртуальное окружение для локальной разработки. Естественно, вы можете все изменить под свои задачи.
Настройки для SQLite
После создания файла базы SQLite (например, с помощью команды touch database/database.sqlite ) необходимо указать тип соединения и абсолютный путь к этому файлу:
1 2 3 4 |
DB_CONNECTION=sqlite DB_DATABASE=/absolute/path/to/database.sqlite |
Настройки для SQL Server
В Laravel встроена поддержка SQL Server. Необходимо добавить настройки соединения в файле config/database.php :
1 2 3 4 5 6 7 8 9 10 11 |
'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-запросов. Laravel с легкостью решает эту проблему, причем вне зависимости от того, как именно вы формируете SQL-запрос: примитивами, построителем запросов или с помощью Eloquent ORM.
Пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
'mysql' => [ 'read' => [ 'host' => '192.168.1.1', ], 'write' => [ 'host' => '196.168.1.2' ], 'sticky' => true, 'driver' => 'mysql', 'database' => 'database', 'username' => 'root', 'password' => '', 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', ], |
Обратите внимание, что добавлено три новых параметра: read, write и sticky. При этом read и write - это массивы всего с одним параметром host. Остальные настройки совпадают для обоих подключений, поэтому вынесены в общую часть массива mysql (это driver, database, ..., prefix).
Чтобы изменить, например, prefix для read-подключения, достаточно добавить этот параметр в массив read. При этом для write-подключения параметр prefix останется прежним (таким, каким он указан в общей части массива mysql).
Параметр sticky
Это опциональный параметр. Если он включен, то любые данные, записанные в течение цикла запроса, могут быть немедленно прочитаны во время этого же запроса.
Использование нескольких подключений
Вы можете создать несколько подключений и явно выбирать необходимое при формировании запроса. Для этого предназначен метод DB::connection(), ожидающий имя подключения, указанное в файле конфигурации config/database.php :
1 2 3 |
$users = DB::connection('foo')->select(...); |
Еще можно получить доступ к базе через объект PDO c помощью метода getPdo():
1 2 3 |
$pdo = DB::connection()->getPdo(); |
Выполнение явных SQL-запросов
После настройки подключения к базе данных, вы можете выполнять запросы с помощью фасада DB, которые предоставляет доступ к методам для каждого типа запросов: select, update, insert, delete и еще statement.
Запрос Select
Можно использовать метод select c фасадом DB:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?php namespace App\Http\Controllers; use Illuminate\Support\Facades\DB; use App\Http\Controllers\Controller; class UserController extends Controller { /** * Show a list of all of the application's users. * * @return Response */ public function index() { $age = 45; $users = DB::select('select * from users where active = ? and age > ?', [1, $age]); return view('user.index', ['users' => $users]); } } |
Первым аргументом этого метода должен быть подготовленный запрос, вторым аргументом - данные для подстановки в этот запрос (биндинг данных). Обычно такая подстановка востребована в условиях where запроса. Данные необходимо передавать именно через второй аргумент для защиты от SQL-инъекций (то есть не стоит делать так: DB::select(' select * from users where age > '.$age).
Подробнее смотрите в документации php.
Метод select всегда возвращает массив объектов strClass с открытым доступом к значениям результата запроса:
1 2 3 4 5 |
foreach ($users as $user) { echo $user->name; } |
Биндинг именованных данных
Вместо символа ? для биндинга данных вы можете использовать именованные параметры:
1 2 3 |
$results = DB::select('select * from users where id = :id', ['id' => 1]); |
Запрос Insert
Можно использовать метод insert c фасадом DB. Как и select, этот метод ожидает первым аргументом подготовленный sql-запрос, вторым - данные для биндинга:
1 2 3 |
DB::insert('insert into users (id, name) values (?, ?)', [1, 'Alex']); |
Запрос Update
Метод update предназначен для обновления существующих записей. Возвращает количество обновленных записей:
1 2 3 |
$affected = DB::update('update users set votes = 100 where name = ?', ['Alex']); |
Запрос Delete
Метод update предназначен для удаления записей. Возвращает количество удаленных записей:
1 2 3 |
$deleted = DB::delete('delete from users'); |
Произвольный запрос
Некоторые запросы не возвращают никаких значений. Для такого вида операций можно использовать метод statement с фасадом DB:
1 2 3 |
DB::statement('drop table users'); |
Обработка событий при запросах
Если вы хотите контролировать каждый sql-запрос вашего приложения, то вам может помочь метод listen. Он может быть полезен, например, для логирования запросов и отладки. Вам следует зарегистрировать свой обработчик в сервис-провайдере:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?php namespace App\Providers; use Illuminate\Support\Facades\DB; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { /** * Bootstrap any application services. * * @return void */ public function boot() { DB::listen(function ($query) { // $query->sql // $query->bindings // $query->time }); } /** * Register the service provider. * * @return void */ public function register() { // } } |
Транзакции
Для выполнения нескольких операций с базой данных в рамках одной транзакции вы можете использовать метод transaction с фасадом DB. Если в замыкании транзакции будет выброшено исключение, то автоматически произойдет откат транзакции, иначе - коммит, то есть нет нужды вручную управлять транзакцией при работе с методом transaction:
1 2 3 4 5 6 7 |
DB::transaction(function () { DB::table('users')->update(['votes' => 1]); DB::table('posts')->delete(); }); |
Обработка взаимоблокировок (deadlocks)
Метод transaction допускает опциональный аргумент, который определяет количество повторных попыток транзакции при обнаружении взаимоблокировок. Когда попытки закончатся, будет выброшено исключение:
1 2 3 4 5 6 7 |
DB::transaction(function () { DB::table('users')->update(['votes' => 1]); DB::table('posts')->delete(); }, 5) |
Работа с транзакциями вручную
Если вы хотите начать транзакцию вручную и затем контролировать коммиты и откаты, то можете использоваться метод beginTransaction с фасадом DB:
1 2 3 |
DB::beginTransaction(); |
Для отката транзакции используйте метод rollback:
1 2 3 |
DB::rollBack(); |
Для коммита - метод commit:
1 2 3 |
DB::commit(); |