查询构造器
Viswoole 的查询构造器提供流畅的链式 API,用于构建和执行数据库查询。通过 Db::table() 获取查询构造器实例。
获取查询构造器
use Viswoole\Database\Facade\Db;
// 获取指定表的查询构造器
$query = Db::table('users');
// 结合通道切换使用
$query = Db::channel('read')->table('users');新增数据 (Create)
insert — 插入单条记录
Db::table('users')->insert([
'name' => '张三',
'email' => 'zhangsan@example.com',
'status' => 1,
]);insertGetId — 插入并返回 ID
当需要获取自增主键时使用此方法:
$userId = Db::table('users')->insertGetId([
'name' => '张三',
'email' => 'zhangsan@example.com',
]);
echo "新用户 ID: {$userId}"; // 输出插入记录的主键值查询数据 (Read)
find — 主键查找
根据主键查询单条记录,返回 DataSet 对象。注意:即使未查询到记录也会返回一个空的 DataSet 对象(而非 null),空 DataSet 在 PHP 中恒为 truthy,因此判断是否有记录应使用 isEmpty()。
// 按 ID 查找
$user = Db::table('users')->find(1);
// 正确判断是否查询到记录
if (!$user->isEmpty()) {
echo $user->name;
}
// 也可以传入 false 禁用空结果返回(此时无记录返回 null)
$user = Db::table('users')->find(1, false);
if ($user) {
echo $user->name;
}first — 获取第一条记录
返回符合条件的第一条记录:
$user = Db::table('users')
->where('status', 1)
->orderBy('created_at', 'desc')
->first();select — 获取多条记录
返回符合条件的所有记录集合:
$users = Db::table('users')
->where('status', 1)
->select();
foreach ($users as $user) {
echo $user->name;
}getArray — 数组形式返回
以纯数组形式返回查询结果(非对象):
$users = Db::table('users')
->where('status', 1)
->getArray();
// 返回格式: [['id' => 1, 'name' => '张三'], ...]cursor — 生成器游标
适用于大数据量查询,通过生成器逐条读取,降低内存占用:
// 逐条处理,内存占用恒定
foreach (Db::table('users')->cursor() as $user) {
// 处理每条记录...
}注意:
cursor()返回的是 Generator 对象,适合一次性处理大量数据。
chunk — 分块处理
将结果按指定数量分批处理,适用于数据迁移、批量导出等场景。chunk() 方法签名为 chunk(int $size): Generator,仅接收分块大小参数,返回一个生成器,每次产出一个 Collection 集合:
// 每次查询 100 条记录,生成器逐批产出 Collection
foreach (Db::table('users')->chunk(100) as $collection) {
foreach ($collection as $user) {
// 处理当前批次的每条记录
}
}注意:
chunk()的参数$size是每次查询的批次大小,生成器会自动翻页并逐批产出Collection对象。
更新数据 (Update)
// 更新指定条件的数据
$affectRows = Db::table('users')
->where('id', 1)
->update(['name' => '李四', 'email' => 'lisi@example.com']);
echo "影响行数: {$affectRows}";
// 多条件更新
Db::table('users')
->where('status', 0)
->where('last_login', '<', '2025-01-01')
->update(['status' => -1]);删除数据 (Delete)
// 按条件删除
$affectRows = Db::table('users')
->where('id', 1)
->delete();
echo "删除行数: {$affectRows}";
// 批量删除
Db::table('users')
->whereIn('id', [10, 11, 12])
->delete();聚合查询
| 方法 | 说明 | 示例 |
|---|---|---|
count() | 统计记录数 | Db::table('users')->count() |
avg() | 计算平均值 | Db::table('users')->avg('age') |
sum() | 求和 | Db::table('orders')->sum('amount') |
min() | 最小值 | Db::table('users')->min('created_at') |
max() | 最大值 | Db::table('users')->max('created_at') |
// 统计用户总数
$total = Db::table('users')->count();
// 计算平均年龄
$avgAge = Db::table('users')->avg('age');
// 订单总金额
$totalAmount = Db::table('orders')->sum('amount');
// 带条件的聚合统计
$activeUserCount = Db::table('users')
->where('status', 1)
->count();条件查询
基础 where
// 等值查询
->where('status', 1)
// 指定运算符
->where('age', '>=', 18)
// 数组形式(AND 条件)— 请使用 wheres() 方法
->wheres([
'name' => '张三',
'status' => 1,
])注意:
where()第一个参数为string类型,不支持传入数组。如需批量设置多个 AND 条件,请使用wheres(array $wheres)方法。
orWhere — 或条件
Db::table('users')
->where('status', 1)
->orWhere('role', 'admin')
->select();
-- SQL: WHERE status = 1 OR role = 'admin'whereIn — IN 查询
->whereIn('id', [1, 2, 3, 4, 5])
->whereNotIn('id', [99, 100]) // NOT INwhereBetween — 区间查询
->whereBetween('age', [18, 60])
->whereNotBetween('age', [0, 17]) // NOT BETWEENwhereNull / whereNotNull — 空值判断
->whereNull('deleted_at') // IS NULL
->whereNotNull('email') // IS NOT NULLwhereGroup — 条件分组(嵌套)
用于构建复杂的括号嵌套条件。whereGroup(array $wheres, string $connector = 'AND') 接收一个条件数组,数组元素支持两种形式:
- 关联键值对:
['字段' => 值],默认使用=运算符和AND连接符 - 索引数组:
['字段', '运算符', '值', '连接符'],第 4 个元素为连接符AND/OR(可选,默认AND)
Db::table('users')
->whereGroup([
['status', '=', 1],
['role', '=', 'admin', 'OR'],
['role', '=', 'super_admin', 'OR'],
])
->select();
-- SQL: WHERE (status = 1 AND role = 'admin' OR role = 'super_admin')如需嵌套分组,可以传入第二个参数指定该组与外部条件的连接方式:
Db::table('users')
->where('type', 'vip')
->whereGroup([
['status', '=', 1],
['role', '=', 'admin', 'OR'],
], 'AND')
->select();
-- SQL: WHERE type = 'vip' AND (status = 1 AND role = 'admin')whereRaw — 原始表达式
当需要使用数据库特有函数或复杂表达式时:
// JSON 字段查询
->whereRaw('JSON_CONTAINS(tags, ?)', ['["php"]'])
// 日期函数
->whereRaw('DATE(created_at) = ?', ['2025-06-22'])原始表达式
使用 Db::raw() 创建原始 SQL 表达式,避免被作为字符串转义:
use Viswoole\Database\Facade\Db;
// 使用 NOW() 函数
Db::table('users')->insert([
'name' => '张三',
'created_at' => Db::raw('NOW()'),
]);
// 自增字段
Db::table('users')
->where('id', 1)
->update([
'login_count' => Db::raw('login_count + 1'),
]);连接查询
join — 内连接
join() 签名:join(string $table, string $localKey, string $foreignKey, string $operator = '=', string $type = 'INNER'),注意运算符在第 4 个参数位置:
Db::table('users u')
->join('orders o', 'u.id', 'o.user_id')
->columns('u.name', 'o.amount', 'o.created_at')
->select();leftJoin — 左连接
注意:
leftJoin()的签名与join()不同:leftJoin(string $table, string $localKey, string $operator, string $foreignKey),运算符在第 3 个参数位置。
Db::table('users u')
->leftJoin('profiles p', 'u.id', '=', 'p.user_id')
->columns('u.*', 'p.avatar', 'p.bio')
->select();rightJoin / fullJoin
rightJoin() 和 fullJoin() 的签名与 join() 一致:运算符在第 4 个参数位置。
// 右连接
->rightJoin('departments d', 'u.dept_id', 'd.id')
// 全连接
->fullJoin('extensions e', 'u.id', 'e.user_id')排序与分页
orderBy — 排序
// 单字段排序
->orderBy('created_at', 'desc')
// 多字段排序
->orderBy('status', 'asc')
->orderBy('created_at', 'desc')page / limit / offset — 分页
// 分页查询(页码, 每页条数)
->page(1, 20)
// 等价于
->limit(20)->offset(0)
// 第二页
->page(2, 20)
-- LIMIT 20 OFFSET 20distinct — 去重
// 获取不重复的角色列表
Db::table('users')
->columns('role')
->distinct()
->select();其他选项
columns 字段选择
注意:字段选择应使用
columns(string...$column): static方法。select(bool $allowEmpty = true)是执行查询的方法,不接受字段参数。
// 选择指定字段
->columns('id', 'name', 'email')
// 别名
->columns('id', Db::raw('COUNT(*) as total'))groupBy / having — 分组
Db::table('orders')
->columns('user_id')
->columns(Db::raw('COUNT(*) as order_count'))
->columns(Db::raw('SUM(amount) as total_amount'))
->groupBy('user_id')
->having('order_count', '>', 5)
->select();alias — 表别名
Db::table('users')
->alias('u')
->columns('u.id', 'u.name')
->select();锁机制
lockForUpdate — 悲观锁(排他锁)
用于防止并发修改,事务提交前其他事务无法修改或读取该记录:
Db::startTransaction(function () {
$user = Db::table('users')
->where('id', 1)
->lockForUpdate()
->first();
// 其他事务在此期间无法修改该记录
$user->balance -= 100;
Db::table('users')->where('id', 1)->update([
'balance' => $user->balance
]);
});sharedLock — 共享锁
允许其他事务读取但不允许修改:
$user = Db::table('users')
->where('id', 1)
->sharedLock()
->first();完整示例
use Viswoole\Database\Facade\Db;
// 复杂查询示例:统计每个分类下活跃用户的订单总额
$result = Db::table('users u')
->alias('u')
->leftJoin('orders o', 'u.id', '=', 'o.user_id')
->columns(
'u.category',
Db::raw('COUNT(DISTINCT u.id) as user_count'),
Db::raw('COALESCE(SUM(o.amount), 0) as total_amount')
)
->where('u.status', 1)
->whereGroup([
['u.role', '=', 'vip', 'OR'],
['u.level', '>=', 5, 'OR'],
])
->whereNotNull('u.email')
->groupBy('u.category')
->having('total_amount', '>', 1000)
->orderBy('total_amount', 'desc')
->page(1, 20)
->getArray();