TP5访问数据库具体实现---query查询器
我们是用Query查询器来完成。使用查询构建器,封装了对于不同数据库的操作,它提供了我们对于不同数据库统一的操作。不需要在意不同数据库差异性。使用原生sql来操作,整个tp5数据库访问层就失去了它的意义。我们一直在说Query是查询构造器。但是这个查询二字就是泛指,它不仅仅是有数据库的读操作,还有写操作。Query构建起仅仅是一种语法,最终还是有Builder来翻译成sql语句来查询。
所有操作数据库都是Db类,查询构建器也是Db类
$result = Db::table("table_name")->where("id","=",$id);
返回了一个对象发现connection和builder是mysql数据库,返回的是Query对象
如果要的到结果必须
$result = Db::table("table_name")->where("id","=",$id)->find();
就是查询结果,但是find()方法只能返回一条数据,返回的是所有属性。
$result = Db::table("table_name")->where("id","=",$id)->select();
返回了二维数组,就是很多条记录
Db::table()->Where()返回的是query对象(链式操作)
只有find()和select()这样两个方法才会最终查询到结果,前面多少链式方法都不会执行sql语句,只有select和find才行
Db是隐藏了数据库具体操作细节,我们只要操作数据库就会使用Db类。table->where这叫辅助方法,或者链式方法。
select和find是真正的查询方法。
前面的辅助方法,无论添加多少都不会执行sql语句,只有用select和find才会执行sql语句。(不只有select和find,还有update,delete,insert) 5个 select find update delete insert 五个执行方法
辅助方法也成为链式方法,这里只有两个,实际上真正编写会有4个,5个
链式方法为什么不会执行sql语句?他为什么像链条这样调用?
辅助方法,链式方法不会真正执行sql语句是因为他每个方法调用后都会返回query对象。正是因为每一个都返回Query对象才可以在查询构建器添加任意多的辅助方法。无论添加多少个链式操作方法,最终得到的总是query对象,query对象里面,才有select,find才会生成sql语句。不同的链式方法没有先后顺序的。因为每一步返回的都是query对象,所以他们之间的顺序没有关系。(这里强调是不同的链式方法)相同的链式方法之间的位置关系是有可能对最终结果产生影响。比如有两个Order他们的先后关系有关系了。如果一个查询构造器出现两个相同链式方法,而你最终生成的sql结果和预期是不一样的,就要排查是不是先后位置关系导致的。可能有影响也不是一定有影响,这个是要根据sql语句来看的。一次Db调用select后状态就被清除了。但是Db::table("a");Db::where(‘condi’);Db::where()。。。。这种就是有关系的。这种非链式调用写法,直到Db::Select();之后状态才会清除。很明显链式调用方法比较‘优雅’,但是一句一写也可以,不过我们儒雅的人要多做优雅的事情。。。
链式方法是很多的,我们最常使用也是比较复杂的是Where,where(‘字段名’,‘表达式’,‘查询条件’);看文档查表达式,EQ和=是一个意思,另外表达式缺省是‘=’,但是缺省也不好,容易让人困惑。
TP5对where还有两种方法,我们这种叫做表达式法,还有数组法,和闭包,而且三种方法可以混合一起用。
数组法不够灵活,也存在安全性问题,一般我们是不用的。
闭包还是不错的,闭包是最灵活的。闭包指的是where里面不是表达式而是传递了匿名函数
$result = Db::table("custom")
->where(function($query){
$query->where(‘id’,"=",$id);
})
->select();
首先匿名函数传递了$query,这个就是查询器的query对象。内部可以拼接不同的链式方法实际上还可以拼接where什么的 ,但是注意不要再query后面调用select语句,这是不对的。在这里就是构建query查询方法,而不能够调用生成sql的语句。这哥id在闭包函数内部是无法读取的,他引用不到id,解决方法是
$result = Db::table("custom")
->where(function($query) use($id){
$query->where(‘id’,"=",$id);
})
->select();
需要use($id)
$result = Db::table("custom")
->fetchsql()
->where(function($query) use($id){
$query->where(‘id’,"=",$id);
})
->select();
我们有2种方法可以看到生成的sql语句,含有比较特殊的链式方法fetchsql(),当加了他即使有了select也不会真实执行,而是会返回sql语句生成结果。 这种方法有局限性。我们通常调试sql是需要获取更加详细的信息,比如sql执行给的时间,还有状态参数,此时fetchsql力不从心。另外简单的查询一个查询构造器是可以的,但是这不是我们代码本身的一部分,这是调试时额外加的,这样就不是太好。加入有很多的需要查,总不能每一个都fetchsql吧。
另外一种是,TP5自动的把我们的sql情况写入日志。要打开自动记录日志我们需要做一些参数配置。打开database的debug默认是true已经打开了,另外的是config(需要debug为true) 在level加入"sql" 另外把type从test改成file(如果改成test一单默认记录日志功能关闭,必须手动初始化相关日志对象)
日志初始化:我们可以再index.php来初始化日志配置。因为所有请求都要经过index.php
thinkLog::init([ "type" => "File", "path" => LOG_PATH, "level" => ["sql"] ]);
我们需要开启这个sql记录,对比ORM的和对应的sql语句这样的效果更好。也非常有利于发现我们的sql查询语句是不是好。因为记录每次的时间,这个对我们的性能调优和找sql错误有非常大的帮助。所以在调试和开发模式把sql开启。生产环境不要去开启,能节约点性能就节约性能,写服务器也要耗费性能。处理问题,发现逻辑不对要找错误原因,可以临时开启,方便找错误。主要是学习和排查错误。性能分析,我们一般使用云端数据库,比如阿里云的rds有很详细的统计性的sql情况,可以很清楚很明白的看到哪个sql语句耗时长。性能调优放到实际项目里面意义并不大。
不过说了这么多我们还是选择ORM对象比较多