菜鸟常忽略的基础 - 记录执行过的SQL ¶
本文导航
作者:KK
发表日期:2016.9.15
阅读前提
请确保你会自定义日志处理器,如果不会的话可以参考我的文章自定义日志处理器
当SQL语句通过Yii底层执行的时候,底层会往消息列表(Yii::getLogger()->messages)追加执行过的SQL语句,那很简单,咱们想办法从消息列表里取出SQL语句就是啦
本文章用日志记录器的方式来记录SQL:
namespace app\ext;
class SqlTarget extends \yii\log\Target{
public function export(){
array_pop($this->messages); //去掉最后一个消息,因为这个与SQL无关,只是底层自动额外追加的一些请求和运行时相关信息
$sqlList = [];
foreach($this->messages as $message){
$sqlList[] = $message[0];
}
$listContent = implode(PHP_EOL, $sqlList);
$sqlNums = count($sqlList);
$logContent = <<<EOL
执行的SQL次数:$sqlNums
执行过的SQL语句:
$listContent
EOL;
$logFile = \Yii::getAlias('@runtime/logs/sql.log');
file_put_contents($logFile, $logContent);
}
}
配置:
'log' => [ //log组件
'targets' => [
[
'class' => 'app\ext\SqlTarget',
'levels' => ['info'],
'categories' => [
'yii\db\Command::query',
'yii\db\Command::execute',
],
],
],
],
相关解读 ¶
关于levels
在上面的配置中levels是
info
,且看yii\db\Command
这个类的execute
和queryInternal
这两个方法都执行了Yii::info($rawSql, ...)
的代码所有SELECT、SHOW等查询语句都是走
queryInternal
方法的而所有INSERT、UPDATE、DELETE这些DML语句(增删改吧反正)就是走
execute
方法的,所以说设置levels为info级别就能记录下所有通过Yii执行的SQL语句了
关于categories
根据官方权威指南的介绍,日志消息除了有级别的区分以外,还有一个区分维度就是分类,这里不详细介绍,而查询语句的分类就是
yii\db\Command::query
,DML语句的分类就是yii\db\Command::execute
因为如果不指定分类的话,会把其它地方的info级别消息都记下来,那不是很坑爹?根本就不是你要的SQL语句嘛,所以消息分类实现了更精准的消息收集