База данных: Конструктор запросов
- 1. Введение
- 2. Выполнение запросов к базе данных
- Select Statements
- Raw Expressions
- Joins
- Unions
- Basic Where Clauses
- Advanced Where Clauses
- Ordering, Grouping, Limit and Offset
- Conditional Clauses
- Insert Statements
- Update Statements
- Delete Statements
- Pessimistic Locking
- Debugging
1. Введение
Конструктор запросов базы данных Laravel предоставляет удобный и гибкий интерфейс для создания и выполнения запросов к базе данных. Он может использоваться для выполнения большинства операций с базой данных в вашем приложении и отлично работает со всеми поддерживаемыми Laravel системами баз данных.
Конструктор запросов Laravel использует привязку параметров PDO для защиты вашего приложения от атак типа SQL-инъекций. Нет необходимости очищать или обрабатывать строки, передаваемые в конструктор запросов в качестве привязок.
PDO не поддерживает привязку имен столбцов. Поэтому никогда не позволяйте пользовательскому вводу определять имена столбцов, упоминаемых в ваших запросах, включая столбцы для операции "order by".
2. Выполнение запросов к базе данных
2.0.1. Получение всех строк из таблицы
Вы можете использовать метод table
, предоставляемый фасадом DB
, чтобы начать построение запроса. Метод table
возвращает экземпляр гибкого конструктора запросов для указанной таблицы, что позволяет добавлять дополнительные ограничения к запросу, а затем получить результаты запроса с помощью метода get
:
<?php namespace App\Http\Controllers; use Illuminate\Support\Facades\DB;use Illuminate\View\View; class UserController extends Controller{ /** * Вывести список всех пользователей приложения. */ public function index(): View { $users = DB::table('users')->get(); return view('user.index', ['users' => $users]); }}
Метод get
возвращает экземпляр Illuminate\Support\Collection
, содержащий результаты запроса, где каждый результат представлен экземпляром объекта PHP stdClass
. Вы можете получить доступ к значению каждого столбца, обратившись к нему как к свойству объекта:
use Illuminate\Support\Facades\DB; $users = DB::table('users')->get(); foreach ($users as $user) { echo $user->name;}
2.0.2. Получение одной строки или одного столбца из таблицы
Если вам нужно получить только одну строку из таблицы базы данных, вы можете использовать метод first
фасада DB
. Этот метод вернет один объект stdClass
:
$user = DB::table('users')->where('name', 'John')->first(); return $user->email;
Если вы хотите получить одну строку из таблицы базы данных, но при отсутствии совпадений выбросить исключение Illuminate\Database\RecordNotFoundException
, вы можете использовать метод firstOrFail
. Если исключение RecordNotFoundException
не будет обработано, клиенту автоматически отправится HTTP-ответ с кодом 404:
$user = DB::table('users')->where('name', 'John')->firstOrFail();
Если вам не нужна вся строка, вы можете извлечь одно значение из записи, используя метод value
. Этот метод вернет значение столбца напрямую:
$email = DB::table('users')->where('name', 'John')->value('email');
Чтобы получить одну строку по значению столбца id
, используйте метод find
:
$user = DB::table('users')->find(3);
2.0.3. Получение списка значений столбца
Если вы хотите получить экземпляр Illuminate\Support\Collection
, содержащий значения одного столбца, вы можете использовать метод pluck
. В этом примере мы получим коллекцию с названиями должностей пользователей:
use Illuminate\Support\Facades\DB; $titles = DB::table('users')->pluck('title'); foreach ($titles as $title) { echo $title;}
Вы можете указать столбец, который должна использовать результирующая коллекция в качестве ключей, передав второй аргумент в метод pluck
:
$titles = DB::table('users')->pluck('title', 'name'); foreach ($titles as $name => $title) { echo $title;}
2.1. Разбиение результатов
Если вам нужно работать с тысячами записей базы данных, рассмотрите возможность использования метода chunk
, предоставляемого фасадом DB
. Этот метод извлекает небольшие части результатов за раз и передает каждую часть в замыкание для обработки. Например, давайте извлечем всю таблицу users
частями по 100 записей:
use Illuminate\Support\Collection;use Illuminate\Support\Facades\DB; DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) { foreach ($users as $user) { // ... }});
Вы можете остановить дальнейшую обработку частей, вернув false
из замыкания:
DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) { // Обработка записей...
return false;});
Если вы обновляете записи базы данных во время обработки результатов частями, ваши результаты могут измениться неожиданным образом. Если вы планируете обновлять полученные записи при разбиении на части, всегда лучше использовать метод chunkById
. Этот метод автоматически разбивает результаты на страницы на основе значения первичного ключа записи:
DB::table('users')->where('active', false) ->chunkById(100, function (Collection $users) { foreach ($users as $user) { DB::table('users') ->where('id', $user->id) ->update(['active' => true]); } });
Поскольку методы chunkById
и lazyById
добавляют свои собственные условия "where" к выполняемому запросу, вам следует обычно логически группировать свои условия внутри замыкания:
DB::table('users')->where(function ($query) { $query->where('credits', 1)->orWhere('credits', 2);})->chunkById(100, function (Collection $users) { foreach ($users as $user) { DB::table('users') ->where('id', $user->id) ->update(['credits' => 3]); }});
При обновлении или удалении записей внутри обратного вызова для метода chunk любые изменения первичного или внешних ключей могут повлиять на запрос для обработки частей. Это может привести к тому, что некоторые записи не будут включены в результаты обработки частями.
2.2. Ленивая загрузка результатов с потоковой передачей
Метод lazy
работает аналогично методу chunk
в том смысле, что он выполняет запрос частями. Однако, вместо передачи каждой части в обратный вызов, метод lazy()
возвращает LazyCollection
, который позволяет взаимодействовать с результатами как с единым потоком:
use Illuminate\Support\Facades\DB; DB::table('users')->orderBy('id')->lazy()->each(function (object $user) { // ...});
Если вы планируете обновлять полученные записи во время их перебора, лучше использовать методы lazyById
или lazyByIdDesc
. Эти методы автоматически разбивают результаты на страницы на основе значения первичного ключа записи:
DB::table('users')->where('active', false) ->lazyById()->each(function (object $user) { DB::table('users') ->where('id', $user->id) ->update(['active' => true]); });
При обновлении или удалении записей во время их перебора любые изменения первичного или внешних ключей могут повлиять на запрос для обработки частей. Это может привести к тому, что некоторые записи не будут включены в результаты.