附录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阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容

  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 4,869评论 0 9
  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 13,347评论 0 15
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,037评论 1 32
  • --- layout: post title: "如果有人问你关系型数据库的原理,叫他看这篇文章(转)" date...
    蓝坠星阅读 750评论 0 3
  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,618评论 0 10