Query Builder: SELECT
Выборка данных — основа работы с базой. Конструктор запросов предоставляет множество методов для гибкой выборки данных из базы. В зависимости от задачи вы можете получить одну запись, список, конкретное значение или выполнить сложный запрос с условиями и соединениями.
Выборка данных
get($columns = ['*'])
Выполняет запрос и возвращает массив объектов stdClass или, если указана модель, массив объектов модели.
use Imhotep\Facades\DB;
// Возвращает все колонки (*)
$users = DB::table('users')->get();
// Выборка определенных колонок
$users = DB::table('users')->get(['name', 'email']);
first($columns = ['*'])
Возвращает первую запись из результата или null.
$user = DB::table('users')->where('id', 1)->first();
firstOr($columns = ['*'], Closure $callback)
Возвращает первую запись или выполняет callback, если запись не найдена.
$user = DB::table('users')->firstOr(['name', 'email'], function () {
return 'Default User';
});
firstOrFail($columns = ['*'], string $message = null)
Возвращает первую запись или выбрасывает исключение RecordNotFoundException.
$user = DB::table('users')->where('email', 'test@test.com')->firstOrFail();
sole($columns = ['*'])
Возвращает единственную запись. Если найдено более одной записи, выбрасывается исключение MultipleRecordsFoundException. Если записей нет — RecordNotFoundException.
$user = DB::table('users')->where('email', 'unique@test.com')->sole();
find($id, $columns = ['*'])
Находит запись по первичному ключу (по колонке id).
$user = DB::table('users')->find(1);
findOr($id, $columns = ['*'], Closure $callback)
Находит запись по ключу или выполняет callback.
$user = DB::table('users')->findOr(1, function () {
return 'User not found';
});
findOrFail($id, $columns = ['*'], string $message = null)
Находит запись по ключу или выбрасывает исключение RecordNotFoundException.
$user = DB::table('users')->findOrFail(1);
value($column, $default = null)
Возвращает значение указанной колонки из первой записи.
$email = DB::table('users')->where('id', 1)->value('email');
soleValue($column)
Возвращает значение колонки из единственной записи или выбрасывает исключение.
$email = DB::table('users')->where('email', 'unique@test.com')->soleValue('email');
pluck($column, $key = null)
Возвращает массив значений указанной колонки. Можно указать колонку для ключей массива.
$names = DB::table('users')->pluck('name');
// ['John', 'Jane', ...]
$users = DB::table('users')->pluck('name', 'id');
// [1 => 'John', 2 => 'Jane', ...]
rawValue($expression, $bindings = [], $default = null)
Выполняет сырое SQL-выражение и возвращает его значение.
$count = DB::table('users')->rawValue('COUNT(*)');
exists()
Проверяет, существуют ли записи, соответствующие запросу.
$exists = DB::table('users')->where('active', true)->exists();
missing()
Проверяет, отсутствуют ли записи, соответствующие запросу (противоположность exists).
$missing = DB::table('users')->where('deleted_at', 'IS NOT NULL')->missing();
Агрегатные функции
-
count($column)— возвращает количество записей -
min($column)— возвращает минимальное значение поля -
max($column)— возвращает максимальное значение поля -
avg($column)— возвращает среднее значение поля -
sum($column)— возвращает сумму значений поля
Выборка колонок
Метод select позволяет указать, какие именно столбцы должны быть включены в результат запроса, это позволит:
- Уменьшить объём передаваемых данных
- Исключить конфиденциальные поля (пароли, токены)
Укажите нужные колонки в виде массива или через запятую:
// SELECT name, email, age FROM users
$users = DB::table('users')->select(['name', 'email', 'age'])->get();
// SELECT name, email, age FROM users
$users = DB::table('users')->select('name', 'email', 'age')->get();
Алиасы колонок
Алиасы позволяют переименовывать столбцы в результатах выборки. Это полезно, когда исходное имя колонки слишком длинное или неудобное:
// SELECT name as full_name, email as user_email FROM users
$users = DB::table('users')
->select('name as full_name', 'email as user_email')
->get();
// SELECT name, YEAR(created_at) as year FROM users
$users = DB::table('users')
->select('name', DB::raw('YEAR(created_at) as year'))
->get();
Выражения в SELECT
Для использования SQL-выражений, агрегатных функций или вычисляемых полей применяйте selectRaw или DB::raw:
use Imhotep\Facades\DB;
// SELECT COUNT(*) as total, YEAR(created_at) as year FROM users GROUP BY year
$users = DB::table('users')
->selectRaw('COUNT(*) as total, YEAR(created_at) as year')
->groupBy('year')
->get();
// SELECT id, name, age > 18 as is_adult FROM users
$users = DB::table('users')
->selectRaw('id, name, age > ? as is_adult', [18])
->get();
Использование привязок (?) защищает от SQL-инъекций — это обязательная практика при подстановке пользовательских данных.
Подзапросы в SELECT
Подзапросы позволяют встраивать один запрос внутрь другого — в данном случае как отдельную колонку в основном запросе. Это удобно, когда нужно получить дополнительные агрегированные или связанные данные для каждой строки без выполнения отдельного запроса в цикле.
Метод selectSub принимает два аргумента, первым сам запрос в виде замыкания или экземпляр Query Builder, вторым название колонки в результатах выборки:
use Imhotep\Facades\DB;
$users = DB::table('users')
->select('name')
->selectSub(function ($query) {
$query->from('posts')
->whereColumn('posts.user_id', 'users.id')
->selectRaw('COUNT(*)');
}, 'posts_count')
->get();
// SELECT name, (SELECT COUNT(*) FROM posts WHERE posts.user_id = users.id) as posts_count FROM users
С использованием готового запроса:
$subQuery = DB::table('orders')
->where('status', 'completed')
->whereColumn('orders.user_id', 'users.id')
->selectRaw('COUNT(*)');
$users = DB::table('users')
->select('id', 'name')
->selectSub($subQuery, 'completed_orders')
->get();
// SELECT id, name, (SELECT COUNT(*) FROM orders WHERE status = 'completed' AND orders.user_id = users.id) as completed_orders FROM users
Уникальные значения (DISTINCT)
Метод distinct исключает дублирующиеся строки в результатах выборки. Особенно полезен, когда нужно получить список уникальных значений из колонки, содержащей повторяющиеся данные:
// SELECT DISTINCT city FROM users
$cities = DB::table('users')->distinct()->select('city')->get();
// SELECT DISTINCT city, country FROM users
$locations = DB::table('users')->distinct()->select('city', 'country')->get();
Условия выборки (WHERE)
Для фильтрации данных существует набор методов where, позволяющих гибко задавать условия:
| Метод | Описание |
|---|---|
where() |
Базовое условие сравнения |
whereRaw() |
Произвольное SQL-выражение |
whereColumn() |
Сравнение двух колонок |
whereNull(), whereNotNull() |
Проверка на NULL |
whereTrue(), whereFalse() |
Проверка на true/false (1 или 0) |
whereIn(), whereNotIn() |
Проверка вхождения в массив |
whereLike(), whereNotLike() |
Поиск по шаблону |
whereDate(), whereYear(), whereMonth(), whereDay(), whereTime(), whereHour(), whereMinute(), whereSecond() |
Сравнение с датой и временем |
whereBetween(), whereNotBetween() |
Проверка вхождения в диапазон |
whereBetweenColumns(), whereNotBetweenColumns() |
Проверка между колонками |
whereExists(), whereNotExists() |
Проверка существования в подзапросе |
Каждый метод имеет парный метод orWhere для создания составных условий с логическим ИЛИ:
$users = DB::table('users')
->where('active', true)
->orWhereNull('deleted_at')
->orWhereIn('role', ['admin', 'moderator'])
->orWhereLike('name', '%guest%')
->orWhereBetween('age', [18, 25])
->orWhereExists(function($query) {
$query->from('subscriptions')
->whereColumn('users.id', 'subscriptions.user_id');
})
->get();
// SELECT * FROM users
// WHERE active = 1
// OR deleted_at IS NULL
// OR role IN ('admin', 'moderator')
// OR name LIKE '%guest%'
// OR age BETWEEN 18 AND 25
// OR EXISTS (SELECT * FROM subscriptions WHERE users.id = subscriptions.user_id)
Базовые условия
С помощью метода where вы можете задавать базовые условия фильтрации в различных форматах:
Формат 1: Строка с условием (парсится автоматически)
$users = DB::table('users')->where('city = Moscow')->get();
$users = DB::table('users')->where('age > 18')->get();
Формат 2: Два параметра (колонка + значение, оператор =)
$users = DB::table('users')->where('active', true)->get();
$users = DB::table('users')->where('city', 'Moscow')->get();
Формат 3: Три параметра (колонка + оператор + значение)
$users = DB::table('users')->where('age', '>', 18)->get();
$users = DB::table('users')->where('name', 'LIKE', '%John%')->get();
$users = DB::table('users')->where('created_at', '>=', '2023-01-01')->get();
Формат 4: Массив условий
$users = DB::table('users')
->where([
'active' => true, // точное сравнение (=)
['age', '>', 18], // сравнение с оператором
'city' => 'Moscow' // точное сравнение (=)
])
->get();
Сырые условия
Если необходимо передать сложное условие в виде обычного SQL, используйте метод whereRaw:
// Простое сырое условие
DB::table('users')->whereRaw('YEAR(age) = 2000')->get();
// С подстановкой параметров (безопасно)
DB::table('users')->whereRaw('YEAR(age) = ?', [2000])->get();
// Несколько параметров
DB::table('users')->whereRaw('age > ? AND city = ?', [18, 'Moscow'])->get();
// Альтернативный способ через DB::raw()
DB::table('users')->where(DB::raw('YEAR(age) = 2000'))->get();
Группировка условий
Для группировки условий в одно логическое выражение используется замыкание внутри where:
$users = DB::table('users')
->where('active', true)
->where(function ($query) {
$query->where('age', '<', 18)
->orWhere('age', '>', 65);
})
->get();
// SELECT * FROM users WHERE active = 1 AND (age < 18 OR age > 65)
Пример с вложенной группировкой:
$users = DB::table('users')
->where(function ($query) {
$query->where('active', true)
->where(function ($subQuery) {
$subQuery->where('age', '>', 18)
->where('city', 'Moscow');
});
})
->orWhere('role', 'admin')
->get();
// SELECT * FROM users
// WHERE (active = 1 AND (age > 18 AND city = 'Moscow')) OR role = 'admin'
Условия с подзапросом
Метод where (с передачей замыкания в качестве значения) позволяет использовать подзапросы:
// Сравнение с результатом подзапроса
$users = DB::table('users')
->where('age', function($query) {
$query->from('settings')
->select('value')
->where('key', 'default_age');
})
->get();
// или
$users = DB::table('users')
->where('age', '>', function($query) {
$query->from('settings')
->select('value')
->where('key', 'default_age');
})
->get();
Сравнение колонок
Метод whereColumn сравнивает значения двух колонок между собой:
// Простое сравнение колонок
$users = DB::table('users')
->whereColumn('created_at', 'updated_at')
->get();
// Сравнение с оператором
$users = DB::table('users')
->whereColumn('price', '>', 'discount_price')
->get();
// Массив сравнений
$users = DB::table('users')
->whereColumn([
['created_at', '>=', 'updated_at'],
['stock', '>', 'min_stock']
])
->get();
Between условия
Методы whereBetween и whereNotBetween проверяют вхождение значения в диапазон:
// Проверка вхождения в диапазон
$users = DB::table('users')
->whereBetween('age', [18, 65])
->get();
// Проверка вне диапазона
$users = DB::table('users')
->whereNotBetween('age', [18, 65])
->get();
// Сравнение колонки с диапазоном между двумя другими колонками
$users = DB::table('users')
->whereBetweenColumns('age', ['min_age', 'max_age'])
->orWhereBetweenColumns('price', ['discount_price', 'regular_price'])
->get();
// С OR-условиями
$users = DB::table('users')
->whereBetween('age', [20, 25])
->orWhereBetween('age', [30, 35])
->get();
Проверка на NULL
// Проверка на NULL
$users = DB::table('users')->whereNull('deleted_at')->get();
// Проверка на NOT NULL
$users = DB::table('users')->whereNotNull('email_verified_at')->get();
// Проверка нескольких колонок
$users = DB::table('users')
->whereNull(['deleted_at', 'archived_at'])
->get();
// OR условия
$users = DB::table('users')
->whereNull('deleted_at')
->orWhereNotNull('archived_at')
->get();
Проверка на true/false
Для булевых значений можно использовать краткую запись:
// Проверка на true
$users = DB::table('users')->where('active', true)->get();
$users = DB::table('users')->whereTrue('active')->get();
// Проверка на false
$users = DB::table('users')->where('active', false)->get();
$users = DB::table('users')->whereFalse('active')->get();
Поиск по списку
Метод whereIn позволяет выполнять поиск по переданному списку значений или подзапросу:
// С массивом значений
$users = DB::table('users')
->whereIn('role', ['admin', 'moderator'])
->get();
// С подзапросом
$users = DB::table('users')
->whereIn('id', function($query) {
$query->from('orders')
->select('user_id')
->where('status', 'active');
})
->get();
Поиск по тексту
Методы whereLike и whereNotLike выполняют текстовый поиск с поддержкой регистра:
// Регистронезависимый поиск (по умолчанию)
$users = DB::table('users')
->whereLike('name', '%john%')
->get();
// Регистрозависимый поиск
$users = DB::table('users')
->whereLike('name', '%John%', true)
->get();
// Поиск с точным совпадением начала строки
$users = DB::table('users')
->whereLike('name', 'John%')
->get();
// Исключение по шаблону
$users = DB::table('users')
->whereNotLike('name', '%admin%')
->get();
// OR условие с LIKE
$users = DB::table('users')
->where('active', true)
->orWhereLike('name', '%guest%')
->get();
Дата и время
Специализированные методы для работы с датами и временем:
Сравнение даты
$users = DB::table('users')
->whereDate('created_at', '2023-01-01')
->orWhereDate('updated_at', '>', '2023-01-05')
->get();
Сравнение года
$users = DB::table('users')
->whereYear('created_at', '2023')
->orWhereYear('created_at', '>=', '2020')
->get();
Сравнение месяца
$users = DB::table('users')
->whereMonth('created_at', '>', 6)
->get();
Сравнение дня
$users = DB::table('users')
->whereDay('created_at', 15)
->get();
Сравнение времени
// C учетом секунд
$users = DB::table('users')
->whereTime('created_at', '>', '12:00:00')
->get();
// Без учета секунд
$users = DB::table('users')
->whereTime('created_at', '=', '20:00')
->get();
Сравнение часа
$users = DB::table('users')
->whereHour('created_at', '>=', 9)
->get();
Сравнение минуты
$users = DB::table('users')
->whereMinute('created_at', 30)
->get();
Сравнение секунды
$users = DB::table('users')
->whereSecond('created_at', 0)
->get();
Проверка наличия (Exists)
Методы whereExists и whereNotExists проверяют существование записей в подзапросе:
// Проверка существования связанных записей
$users = DB::table('users')
->whereExists(function($query) {
$query->from('orders')
->whereColumn('users.id', 'orders.user_id')
->where('orders.status', 'active');
})
->get();
// Проверка отсутствия связанных записей
$users = DB::table('users')
->whereNotExists(function($query) {
$query->from('orders')
->whereColumn('users.id', 'orders.user_id');
})
->get();
// OR EXISTS
$users = DB::table('users')
->where('active', true)
->orWhereExists(function($query) {
$query->from('subscriptions')
->whereColumn('users.id', 'subscriptions.user_id')
->where('subscriptions.active', true);
})
->get();
Работа с JSON
Polymorphic условия (Morph)
Метод whereMorph упрощает работу с полиморфными связями, в качестве значения принимает объект модели:
$post = Post::find(1);
$anyPost = Post::find(2);
$users = DB::table('comments')
->whereMorph('commentable', $post)
->orWhereMorph('commentable', $anyPost)
->get();
Соединения (JOIN)
Соединения позволяют объединять данные из нескольких таблиц. Поддерживаются все основные типы JOIN:
| Тип | Метод | Описание |
|---|---|---|
| INNER JOIN | join() |
Возвращает только совпадающие записи |
| LEFT JOIN | leftJoin() |
Все записи из левой таблицы + совпадающие из правой |
| RIGHT JOIN | rightJoin() |
Все записи из правой таблицы + совпадающие из левой |
| OUTER JOIN | outerJoin() |
Все записи из обеих таблиц |
Примеры использования:
// INNER JOIN
$users = DB::table('users')
->join('posts', 'users.id', '=', 'posts.user_id')
->select('users.name', 'posts.title')
->get();
// LEFT JOIN с несколькими условиями
$users = DB::table('users')
->leftJoin('orders', function($join) {
$join->on('users.id', '=', 'orders.user_id')
->where('orders.status', '=', 'active');
})
->select('users.*', 'orders.total')
->get();
// RIGHT JOIN
$users = DB::table('users')
->rightJoin('roles', 'users.role_id', '=', 'roles.id')
->get();
// OUTER JOIN (FULL OUTER JOIN)
$users = DB::table('users')
->outerJoin('profiles', 'users.id', '=', 'profiles.user_id')
->get();
Сложные условия JOIN
// JOIN с подзапросом
$users = DB::table('users')
->join('orders', function($join) {
$join->on('users.id', '=', 'orders.user_id')
->where('orders.created_at', '>', '2023-01-01');
})
->get();
// JOIN с несколькими условиями
$users = DB::table('users')
->join('orders', function($join) {
$join->on('users.id', '=', 'orders.user_id')
->on('users.status', '=', 'orders.status');
})
->get();
// OR условие в JOIN
$users = DB::table('users')
->join('orders', function($join) {
$join->on('users.id', '=', 'orders.user_id')
->orOn('users.id', '=', 'orders.created_by');
})
->get();
JOIN с подзапросом
// JOIN с подзапросом вместо таблицы
$latestOrders = DB::table('orders')
->select('user_id', DB::raw('MAX(created_at) as latest_order'))
->groupBy('user_id');
$users = DB::table('users')
->joinSub($latestOrders, 'latest_orders', function($join) {
$join->on('users.id', '=', 'latest_orders.user_id');
})
->select('users.*', 'latest_orders.latest_order')
->get();
// Или через замыкание
$users = DB::table('users')
->joinSub(function($query) {
$query->from('orders')
->select('user_id', DB::raw('MAX(created_at) as latest_order'))
->groupBy('user_id');
}, 'latest_orders', function($join) {
$join->on('users.id', '=', 'latest_orders.user_id');
})
->get();
Сортировка данных (ORDER BY)
Метод orderBy сортирует результаты по указанному столбцу, по возрастанию:
// Сортировка по возрастанию
$users = DB::table('users')
->orderBy('name')
->get();
// Множественная сортировка
$users = DB::table('users')
->orderBy('last_name')
->orderBy('first_name')
->orderBy('created_at', 'desc')
->get();
// Сортировка по выражению
$users = DB::table('users')
->orderBy(DB::raw('LENGTH(name)'))
->get();
Для сортировки по убыванию, передайте вторым аргументом 'desc' или используйте метод orderByDesc:
$users = DB::table('users')
->orderByDesc('created_at')
->orderByDesc(['updated_at', 'created_at'])
->get();
// Эквивалентно
$users = DB::table('users')
->orderBy('created_at', 'desc')
->get();
Ограничение записей (LIMIT и OFFSET)
// Ограничение количества записей
$users = DB::table('users')
->limit(10)
->get();
// Пропуск записей (OFFSET)
$users = DB::table('users')
->offset(20)
->limit(10)
->get();
// Взятие первых N записей (take)
$users = DB::table('users')
->take(5)
->get();
Группировка и HAVING
Группировка позволяет агрегировать данные по определенным критериям, а HAVING — фильтровать результаты после группировки.
Группировка (GROUP BY)
// Простая группировка
$users = DB::table('users')
->select('city', DB::raw('COUNT(*) as total'))
->groupBy('city')
->get();
// Группировка по нескольким колонкам
$users = DB::table('users')
->select('city', 'status', DB::raw('COUNT(*) as total'))
->groupBy('city', 'status')
->get();
// Группировка через массив
$users = DB::table('users')
->select('city', DB::raw('AVG(age) as avg_age'))
->groupBy(['city'])
->get();
Для сложных выражений используйте groupByRaw:
$users = DB::table('users')
->select(DB::raw('YEAR(created_at) as year'), DB::raw('COUNT(*) as total'))
->groupByRaw('YEAR(created_at)')
->get();
// С привязками параметров
$users = DB::table('users')
->select(DB::raw('DATE_FORMAT(created_at, ?) as month'), DB::raw('COUNT(*) as total'))
->groupByRaw('DATE_FORMAT(created_at, ?)', ['%Y-%m'])
->get();
Фильтрация групп (HAVING)
HAVING позволяет фильтровать результаты после группировки, в отличие от WHERE, который фильтрует до группировки:
// Базовое условие HAVING
$users = DB::table('users')
->select('city', DB::raw('COUNT(*) as total'))
->groupBy('city')
->having('total', '>', 10)
->get();
// HAVING с OR условием
$users = DB::table('orders')
->select('user_id', DB::raw('COUNT(*) as count_orders'), DB::raw('SUM(amount) as total'))
->groupBy('user_id')
->having('count_orders', '>', 5)
->orHaving('total', '>', 10000)
->get();
Для сложных условий используйте havingRaw:
// Сырое выражение
$users = DB::table('orders')
->select('user_id', DB::raw('SUM(amount) as total'))
->groupBy('user_id')
->havingRaw('SUM(amount) > ?', [1000])
->get();
// С OR условием
$users = DB::table('orders')
->select('user_id', DB::raw('COUNT(*) as count_orders'))
->groupBy('user_id')
->havingRaw('COUNT(*) > 10')
->orHavingRaw('COUNT(*) = 0')
->get();
Сложные логические условия группируются через замыкание:
$users = DB::table('orders')
->select('user_id', DB::raw('SUM(amount) as total'), DB::raw('COUNT(*) as count_orders'))
->groupBy('user_id')
->having(function($query) {
$query->having('total', '>', 1000)
->orHaving('count_orders', '>', 10);
})
->get();
// Вложенные условия с AND/OR
$users = DB::table('orders')
->select('user_id', DB::raw('SUM(amount) as total'), DB::raw('COUNT(*) as count_orders'))
->groupBy('user_id')
->having(function($query) {
$query->having('total', '>', 5000)
->having(function($subQuery) {
$subQuery->having('count_orders', '>', 3)
->orHaving('count_orders', '<', 1);
});
})
->get();
UNION: Объединение запросов
UNION позволяет объединить результаты двух или более запросов в один результирующий набор. Методы union и unionAll дают гибкую возможность комбинировать данные из разных таблиц или запросов.
use Imhotep\Facades\DB;
// Можно передать конструктор запроса
$users = DB::table('users')
->select('name', 'email')
->where('status', 'active')
->union(
DB::table('users_archived')
->select('name', 'email')
->where('status', 'active')
)
->get();
// Или через замыкание
$users = DB::table('users')
->select('name', 'email')
->unionAll(function ($query) {
$query->from('users_archived')->select('name', 'email')
})
->get();
// Для сложных случаев можно передать готовый SQL
$users = DB::table('users')
->select('name', 'email')
->where('active', true)
->union(
"SELECT name, email FROM archived_users WHERE active = ?",
[true] // Привязки параметров
)
->get();
Блокировки (Locking)
Блокировки используются для управления конкурентным доступом к данным в транзакциях. Они помогают предотвратить состояние гонки (race conditions) при одновременной записи и чтении данных.
Важно: Блокировки работают только внутри транзакций. Убедитесь, что вы обернули запросы с блокировками в DB::transaction() или используете их внутри транзакции базы данных.
lockForUpdate() — пессимистичная блокировка на запись
Захватывает блокировку для строк, которые будут обновляться. Другие транзакции не смогут изменить или заблокировать эти строки до завершения текущей транзакции.
Посмотреть пример...
use Imhotep\Facades\DB;
DB::transaction(function () {
// Получаем пользователя с блокировкой для обновления
$user = DB::table('users')
->where('id', 1)
->lockForUpdate()
->first();
// Теперь мы можем безопасно обновить данные
DB::table('users')
->where('id', $user->id)
->update(['balance' => $user->balance - 100]);
});
sharedLock() — общая блокировка на чтение
Захватывает блокировку для чтения данных, которые не должны измениться во время обработки. Другие транзакции также могут читать эти строки, но не могут изменять их до снятия блокировки.
Посмотреть пример...
use Imhotep\Facades\DB;
DB::transaction(function () {
// Получаем данные с общей блокировкой
$report = DB::table('orders')
->where('status', 'pending')
->sharedLock()
->get();
// Формируем отчёт на основе актуальных данных
// Другие транзакции не смогут их изменить, пока мы читаем
});
lock() — пользовательская блокировка
Позволяет передать произвольное выражение блокировки, специфичное для вашей БД.
Посмотреть пример...
use Imhotep\Facades\DB;
DB::transaction(function () {
// MySQL / PostgreSQL: блокировка с ожиданием
$users = DB::table('users')
->where('active', true)
->lock('FOR UPDATE NOWAIT') // Не ждать, если строка заблокирована
->get();
// PostgreSQL: пропустить заблокированные строки
$users = DB::table('users')
->where('status', 'pending')
->lock('FOR UPDATE SKIP LOCKED')
->get();
// MySQL: блокировка только на чтение
$users = DB::table('users')
->lock('LOCK IN SHARE MODE')
->get();
// Обработка данных...
});
lock(false) — отключение блокировки
Явно отключает любую блокировку для запроса. Используется для переопределения блокировок, установленных через модель или глобально.
Посмотреть пример...
use Imhotep\Facades\DB;
DB::transaction(function () {
// Базовый запрос с блокировкой
$baseQuery = DB::table('users')->lockForUpdate();
// Для получения статистики блокировка не нужна
$stats = $baseQuery->lock(false)->selectRaw('count(*) as total')->first();
// Для обновления используем блокировку из базового запроса
$users = $baseQuery->where('active', true)->get();
});