陸續(xù)整理數(shù)據(jù)庫和模型相關(guān)的常見問題(保持更新~)
- 內(nèi)置支持的數(shù)據(jù)庫有哪些?
- Db類封裝的方法看起來很簡單匿情,是如何實現(xiàn)調(diào)用的炬称?
- Db類的內(nèi)部是什么實現(xiàn)原理玲躯?
- 模型和Db類的區(qū)別主要是什么?
table
和name
方法的區(qū)別是什么棘利?- 模型的
get
和all
方法可以支持條件查詢么朽缴? - 模型的
get
和all
方法可以支持排序等鏈?zhǔn)讲僮髅矗?/a> - 閉包查詢?nèi)绾蝹魅胱兞?/a>
- 在模型里面怎么限制查詢字段
- 5.0還有數(shù)據(jù)表字段緩存么密强?
- 獲取器和修改器方法名的規(guī)范是什么或渤?
- 獲取器是在什么時候觸發(fā)?
- 修改器是在什么時候觸發(fā)毕谴?
- 為什么定義的修改器會執(zhí)行兩次
- 如何使用視圖模型涝开?
- 設(shè)置主從分離后,如何切換到主庫進(jìn)行查詢操作
- 如何查詢一個字段值為NULL或者NOT NULL的數(shù)據(jù)拄养?
- 如何直接使用字符串條件進(jìn)行查詢瘪匿?
- 如何切換數(shù)據(jù)庫連接
- 模型中如何使用事務(wù)
- Db類如何使用軟刪除功能
內(nèi)置支持的數(shù)據(jù)庫有哪些寻馏?
5.0
內(nèi)置支持的數(shù)據(jù)庫包括Mysql
诚欠、Sqlite
、Pgsql
和SqlServer
粉寞,另外還提供了Oracle
和MongoDb
的擴(kuò)展驅(qū)動唧垦。
Db類封裝的方法看起來很簡單液样,是如何實現(xiàn)調(diào)用的蓄愁?
Db類只是一個數(shù)據(jù)庫操作的入口類,數(shù)據(jù)庫的查詢方法都是由Query類實現(xiàn)的妇斤,調(diào)用Db類的靜態(tài)方法會自動實現(xiàn)Query類方法的動態(tài)調(diào)用丹拯。并且Db類是一個工廠類,針對不同的數(shù)據(jù)庫驅(qū)動實現(xiàn)了統(tǒng)一的封裝死相。
Db類的內(nèi)部是什么實現(xiàn)原理咬像?
Db類可以看成是數(shù)據(jù)庫抽象訪問層的入口類,抽象訪問層本身包含了連接器類(負(fù)責(zé)連接不同的數(shù)據(jù)庫和執(zhí)行基礎(chǔ)查詢)陷舅、查詢器類(負(fù)責(zé)各種查詢方法的實現(xiàn))和生成器類(負(fù)責(zé)把查詢方法轉(zhuǎn)換為基礎(chǔ)查詢語句)莱睁,各司其職完成了跨數(shù)據(jù)庫的底層操作芒澜,我們只需要操作Db類即可完成數(shù)據(jù)庫抽象訪問層的操作痴晦,系統(tǒng)的數(shù)據(jù)庫抽象訪問層實際上是對PDO的一種擴(kuò)展和增強(qiáng),主要的優(yōu)勢是CURD的增強(qiáng)和查詢事件旨袒,PDO本身只有基礎(chǔ)查詢方法。
模型和Db類的區(qū)別主要是什么施无?
Db類(其實就是數(shù)據(jù)庫抽象訪問層)負(fù)責(zé)數(shù)據(jù)和查詢本身猾骡,而模型類側(cè)重于業(yè)務(wù)邏輯和數(shù)據(jù)處理兴想。Db類僅僅是單純的進(jìn)行操作存取操作,主要使用的是數(shù)組類型捞镰,而模型操作的數(shù)據(jù)主要是模型的對象實例岸售,更加面向?qū)ο蠡椭庇^厂画,并且提供了模型關(guān)聯(lián)操作可以大大簡化業(yè)務(wù)邏輯的相關(guān)處理和數(shù)據(jù)獲取屎慢,模型本身是依賴數(shù)據(jù)庫抽象訪問層的。
table
和name
方法的區(qū)別是什么环肘?
Db類提供了table
和name
兩個方法廷臼,table
方法用于指定數(shù)據(jù)表的完整名稱(包括前綴荠商,而且不會進(jìn)行大小寫轉(zhuǎn)換處理)续誉,name
方法僅僅用于指定數(shù)據(jù)表的標(biāo)識(會把駝峰表名轉(zhuǎn)換為小寫加下劃線的方式酷鸦,并且不包含前綴)。
如果你遵循框架的數(shù)據(jù)表命名規(guī)范嘹裂,并且不使用表前綴的話寄狼,這兩個方法是等效的氨淌。
模型的get
和all
方法可以支持條件查詢么盛正?
可以豪筝,如果模型的get
和all
方法如果傳入一個索引數(shù)組壤蚜,就表示查詢條件,例如:
User::all([
'name' => 'thinkphp',
'id' => ['>', 10],
]);
模型的get
和all
方法可以支持排序等鏈?zhǔn)讲僮髅矗?/h2>
模型類的get和all方法之前不支持Db類的鏈?zhǔn)椒椒ㄕ{(diào)用聪富,如果你需要使用Db類的鏈?zhǔn)椒椒ǘ章梢允褂瞄]包方式,例如:
User::all(function($query){
$query->field('name,email,id')->order('id');
});
等效于
User::field('name,email,id')->order('id')->select();
但區(qū)別是可以支持模型的事件操作昏名。
閉包查詢?nèi)绾蝹魅胱兞?/h2>
如果要在閉包中傳入外部變量轻局,可以使用use
語法仑扑,例如:
User::get(function($query) use($name){
$query->where('name',$name);
});
用類似的方法可以支持傳入多個變量置鼻,下面的用法是錯誤的:
User::get(function($query,$name) {
$query->where('name',$name);
});
在模型里面怎么限制查詢字段
如果在模型里面調(diào)用的是find
或者select
方法箕母,那么依然可以使用field
方法進(jìn)行字段限制,模型類的get
和all
方法查詢的話本身不支持field
方法钙勃,但可以通過閉包完成(參考上一個問題)肺缕。
但并不建議模型查詢的時候指定字段,因為可能會影響模型的獲取器跛十,尤其存在依賴關(guān)系的話秕硝。如果僅僅是希望不暴露敏感數(shù)據(jù)远豺,則可以在輸出數(shù)據(jù)的時候使用hidden
或者visible
方法進(jìn)行隱藏和指定顯示躯护。
5.0還有數(shù)據(jù)表字段緩存么?
5.0默認(rèn)不會生成字段緩存棺滞,但提供了數(shù)據(jù)表字段緩存的命令行指令裁蚁,你可以在部署上線后執(zhí)行php think optimize:schema
命令生成字段緩存矢渊。
獲取器和修改器方法名的規(guī)范是什么?
獲取器和修改器方法的命名規(guī)范分別是getFieldNameAttr
和setFieldNameAttr
枉证,其中的FieldName
是數(shù)據(jù)表字段的駝峰法表示矮男,也就是對應(yīng)數(shù)據(jù)表的field_name
字段。
獲取器是在什么時候觸發(fā)室谚?
獲取器的作用是對模型的數(shù)據(jù)對象的(原始)數(shù)據(jù)做出自動處理毡鉴,定義了獲取器之后會在下列情況自動觸發(fā):
- 模型的數(shù)據(jù)對象取值操作(
$model->field_name
); - 模型的序列化輸出操作(
$model->toArray()
或者$model->toJson()
)秒赤; - 顯式調(diào)用
getAttr
方法($this->getAttr('field_name')
);
修改器是在什么時候觸發(fā)倒脓?
修改器的作用是在寫入數(shù)據(jù)庫之前對模型數(shù)據(jù)進(jìn)行修改處理撑螺,一般在顯式賦值(包括單個賦值和批量賦值)的時候會自動觸發(fā),不過有一些修改器是在設(shè)置了自動完成后被動觸發(fā)崎弃,下面是觸發(fā)條件甘晤。
- 模型對象賦值;
- 調(diào)用模型的data方法饲做,并且第二個參數(shù)傳入true线婚;
- 調(diào)用模型的save方法,并且傳入數(shù)據(jù)盆均;
- 顯式調(diào)用模型的setAttr方法塞弊;
- 定義了該字段的自動完成;
為什么定義的修改器會執(zhí)行兩次
如果定義的修改器字段同時定義了自動完成泪姨,并且你也進(jìn)行了賦值操作游沿,那么就會導(dǎo)致修改器執(zhí)行兩次。避免的方法是對需要賦值操作的字段不再定義自動完成肮砾。典型的場景就是密碼字段使用md5加密保存诀黍,如果定義了自動完成,然后同時表單又賦值了仗处,那么可能會被加密兩次導(dǎo)致出錯眯勾。
如何使用視圖模型?
ThinkPHP提供了多種方式的視圖查詢的支持婆誓,包括:
一吃环、直接在數(shù)據(jù)庫中創(chuàng)建視圖
可以直接在數(shù)據(jù)庫中創(chuàng)建視圖,然后使用Db類或者創(chuàng)建模型類進(jìn)行操作洋幻,這種方式的優(yōu)點是方便郁轻,缺點是有些數(shù)據(jù)庫不支持創(chuàng)建視圖,而且不支持?jǐn)?shù)據(jù)寫入操作鞋屈。
二范咨、使用Db類的view
方法動態(tài)創(chuàng)建視圖查詢
這種方式可以動態(tài)的創(chuàng)建一個視圖并進(jìn)行查詢操作故觅,而不依賴數(shù)據(jù)庫,缺點也是不支持?jǐn)?shù)據(jù)寫入渠啊。
三输吏、使用聚合模型
可以把聚合模型看成是view方法的模型封裝,而且可以支持寫入操作替蛉,缺點是不直觀和配置麻煩贯溅,而且聚合模型和原始模型不能同時使用(最新版本已經(jīng)不再推薦使用)。
四躲查、使用模型關(guān)聯(lián)
最新版本的模型關(guān)聯(lián)對一對一關(guān)聯(lián)改進(jìn)了很多它浅,包括關(guān)聯(lián)屬性綁定到當(dāng)前模型,以及關(guān)聯(lián)自動寫入功能镣煮,這是ThinkPHP5最為推薦的視圖操作方式姐霍,相比前面幾種,優(yōu)勢是操作直觀和支持寫入典唇。
設(shè)置主從分離后镊折,如何切換到主庫進(jìn)行查詢操作
一旦開啟了數(shù)據(jù)庫的主從分離,默認(rèn)情況下所有讀操作都是在從庫介衔,而寫操作則是在主庫恨胚,如果因為某些情況需要(例如對于實時性要求較高的查詢,寫入后立刻查詢從庫同步還不及時的情況)在主庫進(jìn)行查詢炎咖,我們可以使用
Db::name('user')->where('id',10)->update(['name'=>'thinkphp']);
// 連接到主庫進(jìn)行查詢操作
Db::name('user)->master(true)->find(10);
如何查詢一個字段值為NULL或者NOT NULL的數(shù)據(jù)赃泡?
5.0.5
版本開始,可以直接使用快捷查詢方法如下:
// 查詢name為NULL的數(shù)據(jù)
Db::name('user')->whereNull('name')->select();
// 查詢name為NOT NULL的數(shù)據(jù)
Db::name('user')->whereNotNull('name')->select();
如果要使用OR查詢乘盼,可以傳入第二個參數(shù)為OR
// 查詢name為thinkphp或者NULL的數(shù)據(jù)
Db::name('user')->where('name','thinkphp')->whereNull('name','or')->select();
// 查詢name為thinkphp或者NOT NULL的數(shù)據(jù)
Db::name('user')->where('name','thinkphp')->whereNotNull('name','or')->select();
在5.0.5
版本之前升熊,可以使用下面的方式
// 查詢name為NULL的數(shù)據(jù)
Db::name('user')->where('name','null')->select();
// 查詢name為NOT NULL的數(shù)據(jù)
Db::name('user')->where('name','not null')->select();
如何直接使用字符串條件進(jìn)行查詢?
可以在where方法的第一個參數(shù)直接傳入字符串條件绸栅,并且可以和其它條件混合使用:
Db::name('user')
->where('( name like :name OR name IS NULL ) AND id > :id', ['name' => '%think%', 'id' => 10])
->where('email', 'like', '%think')
->select();
如何切換數(shù)據(jù)庫連接
無論在Db類還是模型里面僚碎,要切換數(shù)據(jù)庫都可以直接調(diào)用connect
方法,該方法的參數(shù)可以是數(shù)組或者DNS字符串阴幌,以及配置文件中的數(shù)據(jù)庫連接配置參數(shù)名,例如:
Db::connect('db_config')->name('user')->find();
必須在
connect
方法后面調(diào)用查詢卷中。
模型中如何使用事務(wù)
在模型中使用事務(wù)和數(shù)據(jù)庫中使用事務(wù)一樣矛双,
$this->startTrans();
try{
// 添加實現(xiàn)代碼
// ...
// 提交事務(wù)
$this->commit();
} catch (\Exception $e) {
// 回滾事務(wù)
$this->rollback();
}
但仍然建議直接使用
$this->transaction(function(){
// 添加實現(xiàn)代碼
});
能夠?qū)崿F(xiàn)事務(wù)的自動提交及回滾。
Db類如何使用軟刪除功能
軟刪除功能是模型的特性蟆豫,Db類默認(rèn)不支持议忽,不過5.0.8+
版本開始,可以使用useSoftDelete
方法來支持軟刪除操作十减。
查詢數(shù)據(jù)的時候不包含軟刪除數(shù)據(jù)(假設(shè)軟刪除字段是delete_time
)栈幸。
Db::name('user')->useSoftDelete('delete_time')->select();
上一篇:第九章:性能和安全
下一篇:附錄B:使用MongoDb