附錄A: 常見問題

陸續整理數據庫和模型相關的常見問題(保持更新~)

內置支持的數據庫有哪些?

5.0內置支持的數據庫包括MysqlSqlitePgsqlSqlServer,另外還提供了OracleMongoDb的擴展驅動。

Db類封裝的方法看起來很簡單,是如何實現調用的?

Db類只是一個數據庫操作的入口類,數據庫的查詢方法都是由Query類實現的,調用Db類的靜態方法會自動實現Query類方法的動態調用。并且Db類是一個工廠類,針對不同的數據庫驅動實現了統一的封裝。

Db類的內部是什么實現原理?

Db類可以看成是數據庫抽象訪問層的入口類,抽象訪問層本身包含了連接器類(負責連接不同的數據庫和執行基礎查詢)、查詢器類(負責各種查詢方法的實現)和生成器類(負責把查詢方法轉換為基礎查詢語句),各司其職完成了跨數據庫的底層操作,我們只需要操作Db類即可完成數據庫抽象訪問層的操作,系統的數據庫抽象訪問層實際上是對PDO的一種擴展和增強,主要的優勢是CURD的增強和查詢事件,PDO本身只有基礎查詢方法。

模型和Db類的區別主要是什么?

Db類(其實就是數據庫抽象訪問層)負責數據和查詢本身,而模型類側重于業務邏輯和數據處理。Db類僅僅是單純的進行操作存取操作,主要使用的是數組類型,而模型操作的數據主要是模型的對象實例,更加面向對象化和直觀,并且提供了模型關聯操作可以大大簡化業務邏輯的相關處理和數據獲取,模型本身是依賴數據庫抽象訪問層的。

tablename方法的區別是什么?

Db類提供了tablename兩個方法,table方法用于指定數據表的完整名稱(包括前綴,而且不會進行大小寫轉換處理),name方法僅僅用于指定數據表的標識(會把駝峰表名轉換為小寫加下劃線的方式,并且不包含前綴)。

如果你遵循框架的數據表命名規范,并且不使用表前綴的話,這兩個方法是等效的。

模型的getall方法可以支持條件查詢么?

可以,如果模型的getall方法如果傳入一個索引數組,就表示查詢條件,例如:

User::all([
    'name'  =>  'thinkphp',
    'id'    =>  ['>', 10],
]);

模型的getall方法可以支持排序等鏈式操作么?

模型類的get和all方法之前不支持Db類的鏈式方法調用,如果你需要使用Db類的鏈式方法,可以使用閉包方式,例如:

User::all(function($query){
    $query->field('name,email,id')->order('id');
});

等效于

User::field('name,email,id')->order('id')->select();

但區別是可以支持模型的事件操作。

閉包查詢如何傳入變量

如果要在閉包中傳入外部變量,可以使用use語法,例如:

User::get(function($query) use($name){
    $query->where('name',$name);
});

用類似的方法可以支持傳入多個變量,下面的用法是錯誤的:

User::get(function($query,$name) {
    $query->where('name',$name);
});

在模型里面怎么限制查詢字段

如果在模型里面調用的是find或者select方法,那么依然可以使用field方法進行字段限制,模型類的getall方法查詢的話本身不支持field方法,但可以通過閉包完成(參考上一個問題)。

但并不建議模型查詢的時候指定字段,因為可能會影響模型的獲取器,尤其存在依賴關系的話。如果僅僅是希望不暴露敏感數據,則可以在輸出數據的時候使用hidden或者visible方法進行隱藏和指定顯示。

5.0還有數據表字段緩存么?

5.0默認不會生成字段緩存,但提供了數據表字段緩存的命令行指令,你可以在部署上線后執行php think optimize:schema命令生成字段緩存。

獲取器和修改器方法名的規范是什么?

獲取器和修改器方法的命名規范分別是getFieldNameAttrsetFieldNameAttr,其中的FieldName是數據表字段的駝峰法表示,也就是對應數據表的field_name字段。

獲取器是在什么時候觸發?

獲取器的作用是對模型的數據對象的(原始)數據做出自動處理,定義了獲取器之后會在下列情況自動觸發:

  • 模型的數據對象取值操作($model->field_name);
  • 模型的序列化輸出操作($model->toArray()或者$model->toJson());
  • 顯式調用getAttr方法($this->getAttr('field_name'));

修改器是在什么時候觸發?

修改器的作用是在寫入數據庫之前對模型數據進行修改處理,一般在顯式賦值(包括單個賦值和批量賦值)的時候會自動觸發,不過有一些修改器是在設置了自動完成后被動觸發,下面是觸發條件。

  • 模型對象賦值;
  • 調用模型的data方法,并且第二個參數傳入true;
  • 調用模型的save方法,并且傳入數據;
  • 顯式調用模型的setAttr方法;
  • 定義了該字段的自動完成;

為什么定義的修改器會執行兩次

如果定義的修改器字段同時定義了自動完成,并且你也進行了賦值操作,那么就會導致修改器執行兩次。避免的方法是對需要賦值操作的字段不再定義自動完成。典型的場景就是密碼字段使用md5加密保存,如果定義了自動完成,然后同時表單又賦值了,那么可能會被加密兩次導致出錯。

如何使用視圖模型?

ThinkPHP提供了多種方式的視圖查詢的支持,包括:

一、直接在數據庫中創建視圖

可以直接在數據庫中創建視圖,然后使用Db類或者創建模型類進行操作,這種方式的優點是方便,缺點是有些數據庫不支持創建視圖,而且不支持數據寫入操作。

二、使用Db類的view方法動態創建視圖查詢

這種方式可以動態的創建一個視圖并進行查詢操作,而不依賴數據庫,缺點也是不支持數據寫入。

三、使用聚合模型

可以把聚合模型看成是view方法的模型封裝,而且可以支持寫入操作,缺點是不直觀和配置麻煩,而且聚合模型和原始模型不能同時使用(最新版本已經不再推薦使用)。

四、使用模型關聯

最新版本的模型關聯對一對一關聯改進了很多,包括關聯屬性綁定到當前模型,以及關聯自動寫入功能,這是ThinkPHP5最為推薦的視圖操作方式,相比前面幾種,優勢是操作直觀和支持寫入。

設置主從分離后,如何切換到主庫進行查詢操作

一旦開啟了數據庫的主從分離,默認情況下所有讀操作都是在從庫,而寫操作則是在主庫,如果因為某些情況需要(例如對于實時性要求較高的查詢,寫入后立刻查詢從庫同步還不及時的情況)在主庫進行查詢,我們可以使用

Db::name('user')->where('id',10)->update(['name'=>'thinkphp']);
// 連接到主庫進行查詢操作
Db::name('user)->master(true)->find(10);

如何查詢一個字段值為NULL或者NOT NULL的數據?

5.0.5版本開始,可以直接使用快捷查詢方法如下:

// 查詢name為NULL的數據
Db::name('user')->whereNull('name')->select();
// 查詢name為NOT NULL的數據
Db::name('user')->whereNotNull('name')->select();

如果要使用OR查詢,可以傳入第二個參數為OR

// 查詢name為thinkphp或者NULL的數據
Db::name('user')->where('name','thinkphp')->whereNull('name','or')->select();
// 查詢name為thinkphp或者NOT NULL的數據
Db::name('user')->where('name','thinkphp')->whereNotNull('name','or')->select();

5.0.5版本之前,可以使用下面的方式

// 查詢name為NULL的數據
Db::name('user')->where('name','null')->select();
// 查詢name為NOT NULL的數據
Db::name('user')->where('name','not null')->select();

如何直接使用字符串條件進行查詢?

可以在where方法的第一個參數直接傳入字符串條件,并且可以和其它條件混合使用:

Db::name('user')
    ->where('( name like :name OR name IS NULL ) AND id > :id', ['name' => '%think%', 'id' => 10])
    ->where('email', 'like', '%think')
    ->select();

如何切換數據庫連接

無論在Db類還是模型里面,要切換數據庫都可以直接調用connect方法,該方法的參數可以是數組或者DNS字符串,以及配置文件中的數據庫連接配置參數名,例如:

Db::connect('db_config')->name('user')->find();

必須在connect方法后面調用查詢。

模型中如何使用事務

在模型中使用事務和數據庫中使用事務一樣,

$this->startTrans();
try{
    // 添加實現代碼
    // ...
    // 提交事務
    $this->commit();    
} catch (\Exception $e) {
    // 回滾事務
    $this->rollback();
}

但仍然建議直接使用

$this->transaction(function(){
    // 添加實現代碼
});

能夠實現事務的自動提交及回滾。

Db類如何使用軟刪除功能

軟刪除功能是模型的特性,Db類默認不支持,不過5.0.8+版本開始,可以使用useSoftDelete方法來支持軟刪除操作。

查詢數據的時候不包含軟刪除數據(假設軟刪除字段是delete_time)。

Db::name('user')->useSoftDelete('delete_time')->select();

上一篇:第九章:性能和安全
下一篇:附錄B:使用MongoDb

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,182評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,489評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,290評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,776評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,510評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,866評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,860評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,036評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,585評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,331評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,536評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,058評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,754評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,154評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,469評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,273評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,505評論 2 379

推薦閱讀更多精彩內容

  • ORA-00001: 違反唯一約束條件 (.) 錯誤說明:當在唯一索引所對應的列上鍵入重復值時,會觸發此異常。 O...
    我想起個好名字閱讀 5,403評論 0 9
  • 點擊查看原文 Web SDK 開發手冊 SDK 概述 網易云信 SDK 為 Web 應用提供一個完善的 IM 系統...
    layjoy閱讀 13,853評論 0 15
  • Swift1> Swift和OC的區別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,129評論 1 32
  • --- layout: post title: "如果有人問你關系型數據庫的原理,叫他看這篇文章(轉)" date...
    藍墜星閱讀 807評論 0 3
  • 一、Python簡介和環境搭建以及pip的安裝 4課時實驗課主要內容 【Python簡介】: Python 是一個...
    _小老虎_閱讀 5,795評論 0 10