菜鸟常忽略的基础 - 记录执行过的SQL

本文导航

  1. 相关解读
  • 作者: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

    在上面的配置中levelsinfo,且看yii\db\Command这个类的executequeryInternal这两个方法都执行了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语句嘛,所以消息分类实现了更精准的消息收集