核心模型操作入口
// 推薦:模型類
$user = new \app\model\User;
// 或助手函數
$user = model('User');
// 或 Db 外觀(無模型類)
$user = Db::name('user'); // 表名不含前綴
$user = Db::table('tp_user'); // 完整表名
R - 讀取/查詢
單條記錄
$user->where('id', 1)->find(); // 返回模型對象/數組/null
$user->where('status', 1)->findOrFail(); // 不存在拋異常
$user->where('email', 'a@b.com')->value('name'); // 只取單字段
$user->where('id', 1)->field('id,name')->find(); // 指定字段
多條記錄(集合)
$list = $user->where('status', 1)
->field('id,name,email')
->order('create_time', 'desc')
->limit(10)
->select(); // 返回模型集合/二維數組
// 連貫操作順序任意,select 必須最後
$list = $user->limit(10)->order('id desc')->where('status', 1)->select();
// 參數化查詢(防注入)
$list = $user->where('id', '>', 100)
->where('name', 'like', '%think%')
->select();
查詢構建器表達式(where 進階)
| 表達式 | SQL 等價 | 示例 |
| EQ / = | = | where('id', 1) / where('id', '=', 1) |
| NEQ / != / <> | != | where('id', '!=', 1) |
| GT / > | > | where('score', '>', 90) |
| EGT / >= | >= | where('score', '>=', 90) |
| LT / < | < | where('age', '<', 18) |
| ELT / <= | <= | where('age', '<=', 18) |
| LIKE | LIKE | where('name', 'like', 'think%') |
| NOT LIKE | NOT LIKE | where('name', 'not like', '%test%') |
| IN | IN (...) | where('id', 'in', [1,2,3]) |
| NOT IN | NOT IN (...) | where('id', 'not in', [1,2,3]) |
| BETWEEN | BETWEEN ... AND ... | where('create_time', 'between', ['2024-01-01', '2024-12-31']) |
| NOT BETWEEN | NOT BETWEEN | where('age', 'not between', [18, 60]) |
| EXP | 原生表達式 | where('id', 'exp', 'IN (SELECT uid FROM logs)') |
| NULL / NOTNULL | IS NULL | where('deleted_at', 'null') |
多條件組合
// AND(默認)
$user->where('a', 1)->where('b', 2);
// OR
$user->where('a', 1)->whereOr('b', 2);
// 複雜嵌套
$user->where(function($query) {
$query->where('a', 1)->whereOr('b', 2);
})->where('c', 3);
// (a=1 OR b=2) AND c=3
聚合/統計
$user->where('status', 1)->count(); // 總數
$user->where('status', 1)->sum('score'); // 求和
$user->where('status', 1)->avg('score'); // 平均
$user->where('status', 1)->max('score'); // 最大值
$user->where('status', 1)->min('score'); // 最小值
分頁
// 方式一:paginate 自動處理頁碼、生成鏈接
$page = $user->where('status', 1)->paginate(15); // 每頁 15 條
// 模板:{$page->render()} 輸出分頁 HTML
// 方式二:手動 page/limit
$list = $user->where('status', 1)->page(2, 15)->select(); // 第 2 頁,每頁 15
C - 創建/新增
$data = ['name' => 'Tom', 'email' => 'tom@example.com', 'status' => 1];
// 方式一:模型 save(觸發事件、驗證、自動寫入時間戳)
$user = new User($data);
$user->save(); // 返回 bool,主鍵自動回填 $user->id
// 方式二:靜態 create(鏈式)
$user = User::create($data); // 返回模型實例或 false
// 方式三:Db 外觀 insertGetId
$id = Db::name('user')->insertGetId($data);
// 批量插入
Db::name('user')->insertAll([
['name' => 'A', 'email' => 'a@b.com'],
['name' => 'B', 'email' => 'b@c.com'],
]); // 返回影響行數
U - 更新
$data = ['name' => 'Jerry', 'score' => 100];
// 方式一:模型 save(需先查詢或實例化主鍵)
$user = User::find(1);
$user->name = 'Jerry';
$user->save(); // 只有髒數據才執行 UPDATE
// 方式二:靜態 update
User::update($data, ['id' => 1]); // 返回影響行數
// 方式三:Db 外觀
Db::name('user')->where('id', 1)->update($data);
// 增量更新(原子操作)
Db::name('user')->where('id', 1)->inc('score', 10); // score += 10
Db::name('user')->where('id', 1)->dec('score', 5); // score -= 5
D - 刪除
delete(); // 條件刪除
// 硬刪除(永久)
User::where('id', 1)->delete(true); // true = force
Db::name('user')->where('id', 1)->delete();
多表查詢
join 關聯
$list = Db::name('order')
->alias('o')
->join('user u', 'o.user_id = u.id', 'LEFT')
->join('goods g', 'o.goods_id = g.id')
->field('o.id, o.price, u.name as buyer, g.title')
->select();
// join 可多次鏈式調用,支持 LEFT/RIGHT/INNER
table 指定多表
Db::table('tp_order o, tp_user u')
->where('o.user_id = u.id')
->field('o.*, u.name')
->select();
其他常用鏈式操作
| 方法 | 用途 | 示例 |
| field | 指定查詢字段 | field('id,name') / field(['id', 'name' => 'nickname']) |
| order | 排序 | order('id desc') / order(['id' => 'desc', 'score' => 'asc']) |
| limit | 限制條數 | limit(10) / limit(5, 10) (offset, limit) |
| page | 分頁簡寫 | page(2, 15) |
| group | 分組 | group('category_id') |
| having | 分組過濾 | having('count(*) > 5') |
| distinct | 去重 | distinct(true)->field('category_id')->select() |
| lock | 行鎖 | lock(true) (FOR UPDATE) / lock(false) (LOCK IN SHARE MODE) |
| cache | 查詢緩存 | cache('key', 3600) / cache(true, 3600, 'custom_tag') |
| comment | SQL 註釋 | comment('查詢活躍用戶') |
| force | 強制索引 | force('idx_status') |
| master/slave | 主從分離 | master()->select() 強制主庫 |
調試 SQL
$user->where('id', 1)->find();
echo $user->getLastSql(); // 顯示最後執行的 SQL(含綁定參數)
// 或配置 app/database.php: 'debug' => true 記錄所有 SQL 到日誌
最佳實踐提醒
- 業務邏輯盡量寫在 **Model** 類方法中,控制器保持輕量。
- 使用 **模型事件** (
static function init() 註冊) 自動處理創建/更新時間、軟刪除、關聯刪除。
- 開啟 **字段類型轉換** (
$type = ['score' => 'integer']) 保證數據純淨。
- 複雜報表查詢直接寫 **原生 SQL** (
Db::query()) 而非強行鏈式構建。
- 生產環境關閉
app_debug,開啟 sql_explain 慢查詢日誌。