# 查詢
模型查詢和數據庫查詢方法的區別主要在于,模型中的查詢的數據在獲取的時候會經過獲取器的處理,以及更加對象化的獲取方式。
> 模型查詢除了使用自身的查詢方法外,一樣可以使用數據庫的查詢構造器,返回的都是模型對象實例。但如果直接調用查詢對象的方法,IDE可能無法完成自動提示。
## 獲取單個數據
獲取單個數據的方法包括:
```
// 取出主鍵為1的數據
$user = User::get(1);
echo $user->name;
// 使用查詢構造器查詢滿足條件的數據
$user = User::where('name', 'thinkphp')->find();
echo $user->name;
```
模型無論使用`get`還是`find`方法查詢,返回的是都當前模型的對象實例,除了獲取模型數據外,還可以使用模型的方法。
> `V5.1.5+`版本,模型增加了`getOrFail`方法用于查詢,當查詢的數據不存在的時候會拋出`ModelNotFound`異常。
> 如果你是在模型內部獲取模型數據,請不要使用`$this->name`的方式來獲取數據,請使用`$this->getAttr('name')` 替代。
## 獲取多個數據
取出多個數據:
```
// 根據主鍵獲取多個數據
$list = User::all('1,2,3');
// 或者使用數組
$list = User::all([1,2,3]);
// 對數據集進行遍歷操作
foreach($list as $key=>$user){
echo $user->name;
}
```
要更多的查詢支持,一樣可以使用查詢構造器:
```
// 使用查詢構造器查詢
$list = User::where('status', 1)->limit(3)->order('id', 'asc')->select();
foreach($list as $key=>$user){
echo $user->name;
}
```
> 查詢構造器方式的查詢可以支持更多的連貫操作,包括排序、數量限制等。
### 自定義數據集對象
模型的`all`方法或者`select`方法返回的是一個包含多個模型實例的數據集對象(默認為`\think\model\Collection`),支持在模型中單獨設置查詢數據集的返回對象的名稱,例如:
```
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// 設置返回數據集的對象名
protected $resultSetType = '\app\common\Collection';
}
```
`resultSetType`屬性用于設置自定義的數據集使用的類名,該類應當繼承系統的`think\model\Collection`類。
## 使用查詢構造器
在模型中仍然可以調用數據庫的鏈式操作和查詢方法,可以充分利用數據庫的查詢構造器的優勢。
例如:
```
User::where('id',10)->find();
User::where('status',1)->order('id desc')->select();
User::where('status',1)->limit(10)->select();
```
使用查詢構造器直接使用靜態方法調用即可,無需先實例化模型。
### 獲取某個字段或者某個列的值
```
// 獲取某個用戶的積分
User::where('id',10)->value('score');
// 獲取某個列的所有值
User::where('status',1)->column('name');
// 以id為索引
User::where('status',1)->column('name','id');
```
> `value`和`column`方法返回的不再是一個模型對象實例,而是純粹的值或者某個列的數組。
### 動態查詢
支持數據庫的動態查詢方法,例如:
```
// 根據name字段查詢用戶
$user = User::getByName('thinkphp');
// 根據email字段查詢用戶
$user = User::getByEmail('thinkphp@qq.com');
```
### 聚合查詢
同樣在模型中也可以調用數據庫的聚合方法查詢,例如:
```
User::count();
User::where('status','>',0)->count();
User::where('status',1)->avg('score');
User::max('score');
```
### 數據分批處理
模型也可以支持對返回的數據分批處理,這在處理大量數據的時候非常有用,例如:
```
User::chunk(100,function($users) {
foreach($users as $user){
// 處理user模型對象
}
});
```
## 使用游標查詢
模型也可以使用數據庫的`cursor`方法進行游標查詢,返回生成器對象
```
foreach(User::where('status', 1)->cursor() as $user){
echo $user->name;
}
```
`user`變量是一個模型對象實例。
## 查詢緩存
`get`方法和`all`方法的支持使用查詢緩存,可以直接在第二個參數傳入true表示開啟查詢緩存。
```
$user = User::get(1,true);
$list = User::all('1,2,3',true);
```
如果要設置緩存標識,則必須在第三個參數傳入緩存標識。
```
$user = User::get(1,'','user');
$list = User::all('1,2,3','','user_list');
```
## 主庫讀取
如果你采用分布式數據庫,如果寫入數據后立刻進行該數據的讀取,將會導致數據讀取失敗,原因是數據庫同步尚未完成。
規范的解決方案是在寫入數據后,不要馬上從從庫讀取,而應該調用`master`方法讀取主庫。
```
$user = new User;
$user->name = 'thinkphp';
$user->email = 'thinkphp@qq.com';
$user->save();
// 從主庫讀取數據
$user->master()->get($user->id);
```
或者對關鍵的邏輯啟用事務,在事務中的數據庫操作都是基于主庫的。
`V5.1.12+`版本開始,你可以在數據庫配置文件中設置
```
// 主庫寫入后從主從庫讀取
'read_master' => true
```
設置開啟后,一旦你的模型有寫入操作,那么該請求后續的同一個模型的讀操作都會自動從主庫讀取。
如果你只需要對某個模型生效,可以在你完成主庫寫入操作后,執行下模型類的`readMaster`方法。
```
$user = new User;
$user->name = 'thinkphp';
$user->email = 'thinkphp@qq.com';
$user->save();
// 從主庫讀取數據
$user->readMaster(true)->get($user->id);
```
> 注意上述設置和方法僅對模型查詢有效,直接調用Db類查詢無效。
## 最佳實踐
> 模型查詢的最佳實踐原則是:在模型外部使用靜態方法進行查詢,內部使用動態方法查詢,包括使用數據庫的查詢構造器。模型的查詢始終返回對象實例,但可以和數組一樣使用。
- 序言
- 基礎
- 安裝
- 開發規范
- 目錄結構
- 配置
- 架構
- 架構總覽
- 入口文件
- URL訪問
- 模塊設計
- 命名空間
- 容器和依賴注入
- Facade
- 鉤子和行為
- 中間件
- 路由
- 路由定義
- 變量規則
- 路由地址
- 閉包支持
- 路由參數
- 路由緩存
- 跨域請求
- 注解路由
- 路由分組
- MISS路由
- 資源路由
- 快捷路由
- 路由別名
- 路由綁定
- 域名路由
- URL生成
- 控制器
- 控制器定義
- 前置操作
- 跳轉和重定向
- 空操作和空控制器
- 分層控制器
- 資源控制器
- 請求
- 請求對象
- 請求信息
- 輸入變量
- 請求類型
- HTTP頭信息
- 偽靜態
- 參數綁定
- 請求緩存
- 響應
- 響應輸出
- 響應參數
- 重定向
- 數據庫
- 連接數據庫
- 查詢構造器
- 查詢數據
- 添加數據
- 更新數據
- 刪除數據
- 查詢表達式
- 鏈式操作
- 聚合查詢
- 時間查詢
- 高級查詢
- 視圖查詢
- JSON字段
- 子查詢
- 原生查詢
- 查詢事件
- 事務操作
- 監聽SQL
- 存儲過程
- 數據集
- 分布式數據庫
- 模型
- 定義
- 新增
- 更新
- 刪除
- 查詢
- JSON字段
- 獲取器
- 修改器
- 自動時間戳
- 只讀字段
- 軟刪除
- 類型轉換
- 數據完成
- 查詢范圍
- 模型輸出
- 模型事件
- 模型關聯
- 一對一關聯
- 一對多關聯
- 遠程一對多
- 多對多關聯
- 多態關聯
- 關聯預載入
- 關聯統計
- 關聯輸出
- 視圖
- 視圖渲染
- 視圖賦值
- 視圖過濾
- 模板引擎
- 模板
- 變量輸出
- 使用函數
- 運算符
- 原樣輸出
- 模板注釋
- 模板布局
- 模板繼承
- 包含文件
- 輸出替換
- 標簽庫
- 內置標簽
- 循環標簽
- 比較標簽
- 條件判斷
- 資源文件加載
- 標簽嵌套
- 原生PHP
- 定義標簽
- 標簽擴展
- 錯誤和日志
- 異常處理
- 日志處理
- 調試
- 調試模式
- Trace調試
- 性能調試
- SQL調試
- 變量調試
- 遠程調試
- 驗證
- 驗證器
- 驗證規則
- 錯誤信息
- 驗證場景
- 路由驗證
- 內置規則
- 獨立驗證
- 靜態調用
- 表單令牌
- 雜項
- 緩存
- Session
- Cookie
- 多語言
- 分頁
- 上傳
- 命令行
- 啟動內置服務器
- 自動生成目錄結構
- 創建類庫文件
- 生成類庫映射文件
- 清除緩存文件
- 生成配置緩存文件
- 生成數據表字段緩存
- 生成路由映射緩存
- 自定義指令
- 擴展庫
- 驗證碼
- 圖像處理
- Time
- 數據庫遷移工具
- Workerman
- MongoDb
- 單元測試
- 安全和性能
- 安全建議
- 優化建議
- 附錄
- 助手函數
- 升級指導
- 更新日志