YII2框架查询源码解析
来源:互联网 发布:淘宝上怎么买av的资源 编辑:程序博客网 时间:2024/06/09 21:32
首先看findOne的函数定义,该函数定义在BaseActiveRecord当中
- return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
findOne定义是:
- public static function findOne($condition)
- {
- return static::findByCondition($condition)->one();
- }
也就是说我们需要看一下findByCondition的函数的定义,该函数定义在BaseActiveRecord
- protected static function findByCondition($condition)
- {
- $query = static::find();
- if (!ArrayHelper::isAssociative($condition)) {
- // query by primary key
- $primaryKey = static::primaryKey();
- if (isset($primaryKey[0])) {
- $condition = [$primaryKey[0] => $condition];
- } else {
- throw new InvalidConfigException('"' . get_called_class() . '" must have a primary key.');
- }
- }
- return $query->andWhere($condition);
- }
find函数的定义是在ActiveRecord类中定义的
- public static function find()
- {
- return Yii::createObject(ActiveQuery::className(), [get_called_class()]);
- }
也就是说$query是一个ActiveQuery的对象,其需要传入的参数是需要进行查询的类的名字"User";
中间这一部分,先不要看,因为还没时间看,直接看下面的一行addWhere该函数的定义是在Query类中
- public function andWhere($condition, $params = [])
- {
- if ($this->where === null) {
- $this->where = $condition;
- } else {
- $this->where = ['and', $this->where, $condition];
- }
- $this->addParams($params);
- return $this;
- }
在这里仅仅是将传入的参数$condition,付给ActiveQuery的where成员变量。到此findByCondition已经执行完成,开始执行one函数。该函数定义在ActiveQuery类当中
- public function one($db = null)
- {
- $row = parent::one($db);
- if ($row !== false) {
- $models = $this->populate([$row]);
- return reset($models) ?: null;
- } else {
- return null;
- }
- }
首先调用父类Query的one函数,该函数定义如下:
- public function one($db = null)
- {
- return $this->createCommand($db)->queryOne();
- }
这里就需要看一下createCommand函数,该函数的定义是:
- public function createCommand($db = null)
- {
- if ($db === null) {
- $db = Yii::$app->getDb();
- }
- list ($sql, $params) = $db->getQueryBuilder()->build($this);
- return $db->createCommand($sql, $params);
- }
这里可以看到需要获得数据库链接配置,然后创建queryBuilder对象,并利用build模式构建完整的sql语句
- public function build($query, $params = [])
- {
- $query = $query->prepare($this);
- $params = empty($params) ? $query->params : array_merge($params, $query->params);
- $clauses = [
- $this->buildSelect($query->select, $params, $query->distinct, $query->selectOption),
- $this->buildFrom($query->from, $params),
- $this->buildJoin($query->join, $params),
- $this->buildWhere($query->where, $params),
- $this->buildGroupBy($query->groupBy),
- $this->buildHaving($query->having, $params),
- ];
- $sql = implode($this->separator, array_filter($clauses));
- $sql = $this->buildOrderByAndLimit($sql, $query->orderBy, $query->limit, $query->offset);
- if (!empty($query->orderBy)) {
- foreach ($query->orderBy as $expression) {
- if ($expression instanceof Expression) {
- $params = array_merge($params, $expression->params);
- }
- }
- }
- if (!empty($query->groupBy)) {
- foreach ($query->groupBy as $expression) {
- if ($expression instanceof Expression) {
- $params = array_merge($params, $expression->params);
- }
- }
- }
- $union = $this->buildUnion($query->union, $params);
- if ($union !== '') {
- $sql = "($sql){$this->separator}$union";
- }
- return [$sql, $params];
- }
好吧,看看这个吧!!!
这一部分使用了build模式,进行创建整个sql语句下面的几个函数就先不说了,因为这一部分就是分部分进行构建查询语句,分部分构建select from join where group having
每个函数都构建了一部分语句,最后各个部分语句形成了$clauses是由各部分语句的数组。最后返回$sql, $param的数组,得到$sql之后可以继续执行了,,接下来创建$command
- return $db->createCommand($sql, $params);
- public function createCommand($sql = null, $params = [])
- {
- /** @var Command $command */
- $command = new $this->commandClass([
- 'db' => $this,
- 'sql' => $sql,
- ]);
- return $command->bindValues($params);
- }
bindValues函数如下:
- public function bindValues($values)
- {
- if (empty($values)) {
- return $this;
- }
- $schema = $this->db->getSchema();
- foreach ($values as $name => $value) {
- if (is_array($value)) {
- $this->_pendingParams[$name] = $value;
- $this->params[$name] = $value[0];
- } else {
- $type = $schema->getPdoType($value);
- $this->_pendingParams[$name] = [$value, $type];
- $this->params[$name] = $value;
- }
- }
- return $this;
- }
- public function queryOne($fetchMode = null)
- {
- return $this->queryInternal('fetch', $fetchMode);
- }
queryInternal函数定义
- protected function queryInternal($method, $fetchMode = null)
- {
- $rawSql = $this->getRawSql();
- Yii::info($rawSql, 'yii\db\Command::query');
- if ($method !== '') {
- $info = $this->db->getQueryCacheInfo($this->queryCacheDuration, $this->queryCacheDependency);
- if (is_array($info)) {
- /* @var $cache \yii\caching\Cache */
- $cache = $info[0];
- $cacheKey = [
- __CLASS__,
- $method,
- $fetchMode,
- $this->db->dsn,
- $this->db->username,
- $rawSql,
- ];
- $result = $cache->get($cacheKey);
- if (is_array($result) && isset($result[0])) {
- Yii::trace('Query result served from cache', 'yii\db\Command::query');
- return $result[0];
- }
- }
- }
- $this->prepare(true);
- $token = $rawSql;
- try {
- Yii::beginProfile($token, 'yii\db\Command::query');
- $this->pdoStatement->execute();
- if ($method === '') {
- $result = new DataReader($this);
- } else {
- if ($fetchMode === null) {
- $fetchMode = $this->fetchMode;
- }
- $result = call_user_func_array([$this->pdoStatement, $method], (array) $fetchMode);
- $this->pdoStatement->closeCursor();
- }
- Yii::endProfile($token, 'yii\db\Command::query');
- } catch (\Exception $e) {
- Yii::endProfile($token, 'yii\db\Command::query');
- throw $this->db->getSchema()->convertException($e, $rawSql);
- }
- if (isset($cache, $cacheKey, $info)) {
- $cache->set($cacheKey, [$result], $info[1], $info[2]);
- Yii::trace('Saved query result in cache', 'yii\db\Command::query');
- }
- return $result;
- }
这样看来,就是讲所有的查询结果进行返回,那么会有人问不是findOne吗?在哪里进行的取one操作呢?是在ActiveQuery的one操作中,父类得到所有的查询结果,子类将查询结果进行reset操作,将第一行记录返回
查询总览:
所有的都是这样查询的static::findOne(条件),findOne函数定义是在BaseActiveRecord类中定义的,因为当前使用的User类的父类是ActiveRecord而ActiveRecord的父类是BaseActiveRecord
在此调用的是findByCondition在该函数中获得了ActiveQuery类的对象,同时传入需要修改的类的名称(需要调用该类的静态函数tableName,获得表名称),并且在findByCondition中将条件数组转成
String,方便继续使用,继续调用ActiveQuery的addWhere记录下ActiveQuery的where条件,之后调用Query的one()函数,在Query的one函数中创建了yii\db\Connection类的对象,继续调用该db对象的getQueryBuilder函数,创建了一个QueryBuilder对象,然后在QUeryBuilder对象中进行完整的sql构造,将sql查询语句中可能出现的各个子查询都进行分别处理,各部分处理结果得到一个字符串,将这部分字符串组成数组,在展开implode,合成一个sql语句,将生成的sql语句传递给由yii\db\Connection创建的yii\db\command对象,并进行执行queryOne函数该函数调用queryInternal并返回结果集,最后由ActiveQuery的one函数进行reset操作,返回第一个结果记录
0 0
- YII2框架查询源码解析
- yii2查询条件Where全解析
- yii2.0框架深入解析学习
- MPlayer 源码框架解析
- ci框架源码解析
- 源码解析Volley框架
- openwrt源码框架解析
- openwrt源码框架解析
- Volley框架源码解析
- volley框架源码解析
- LeakCanary框架源码解析
- Logger框架源码解析
- PHP CodeIgniter框架源码解析
- 宏观解析jQuery框架源码
- 宏观解析jQuery框架源码
- 关于volley框架源码解析
- dubbo框架源码核心技术解析
- OKHttp网络框架源码解析
- LintCode:两数组的交
- 基于qualcomm平台的kinect应用系列一之Turtlebot(自动跟随机器人)下篇
- filename and pathname
- java synchronized详解
- Gulp.js入门小教程
- YII2框架查询源码解析
- Openssl的编译安装以及Vs2012上环境搭建教程
- 算法导论第一节学习笔记
- 程序背后那些事
- Intellij IDEA集成tortoiseSVN问题解决
- 关于函数实参和形参的地址传送
- 1035 最长的循环节
- Html编码(&#数字型)解码
- 信号