yii2的数据库层设计

   2017-02-05 0
核心提示:Yii2在M层的抽象做的很经典,值得分析理解。QueryBuilder不同的数据库引擎(mysql,oracle…)执行相同的SQL,可能语法有一些细微的差异,但是SQL整体语法差别不大,所以会定义一个QueryBuilder基类,它提供一般通用的SQL生成方法,具体每个数据库引擎继承Quer

Yii2在M层的抽象做的很经典,值得分析理解。

QueryBuilder

不同的数据库引擎(mysql,oracle…)执行相同的SQL,可能语法有一些细微的差异,但是SQL整体语法差别不大,所以会定义一个QueryBuilder基类,它提供一般通用的SQL生成方法,具体每个数据库引擎继承QueryBuilder,如果存在细微差异只需覆盖特定的方法既可。

简单说,QueryBuilder用来构造SQL语句(读SQL和写SQL都可以),但是并不执行它,通过调用它的where,groupBy,orderBy,select,insert等方法传入结构化的语句组成部分,最终由QueryBuilder返回一个字符串的SQL语句。

Query

仅提供查询能力,不支持修改,它也提供where,groupBy,select等方法(注意不支持insert,update这种修改操作),但是它本身没有生成SQL的能力,仅仅是在QueryBulder之上提供一个通用层,最终在调用它的one或者all方法时会将SQL的各个组成部分一次性交给QueryBuilder构造出SQL语句,那么Query对象怎么知道用哪个QueryBuilder呢?

Query对象会通过application->get(“db”)拿到配置的数据库连接connection对象,这个connection对象自然是知道自己连接的是哪种数据库引擎,因此可以通过它拿到对应的queryBuilder对象。具体来说,connection对象创建时会从配置中取到这样的配置:

return [
    'components' => [
        'db' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'mysql:host=localhost;dbname=yii2advanced',
            'username' => 'root',
            'password' => '',
            'charset' => 'utf8',
        ],

Connection对象根据dsn知道对应的数据库引擎,从而创建对应的schema对象:

public $schemaMap = [
    'pgsql' => 'yii\db\pgsql\Schema', // PostgreSQL
    'mysqli' => 'yii\db\mysql\Schema', // MySQL
    'mysql' => 'yii\db\mysql\Schema', // MySQL
    'sqlite' => 'yii\db\sqlite\Schema', // sqlite 3
    'sqlite2' => 'yii\db\sqlite\Schema', // sqlite 2
    'sqlsrv' => 'yii\db\mssql\Schema', // newer MSSQL driver on MS Windows hosts
    'oci' => 'yii\db\oci\Schema', // Oracle driver
    'mssql' => 'yii\db\mssql\Schema', // older MSSQL driver on MS Windows hosts
    'dblib' => 'yii\db\mssql\Schema', // dblib drivers on GNU/Linux (and maybe other OSes) hosts
    'cubrid' => 'yii\db\cubrid\Schema', // CUBRID
];

而这个Schema对象是每个数据库引擎各自实现的,它们有一个方法可以返回对应的QueryBuilder对象:

/**
* @return QueryBuilder the query builder for this connection.
*/
public function getQueryBuilder()
{
    if ($this->_builder === null) {
        $this->_builder = $this->createQueryBuilder();
    }
 
    return $this->_builder;
}

但是需要注意,虽然经过QueryBuilder生成了SQL,但是Query并不是自己直接执行这个SQL,而是将这个任务交给了下面这个类。

Command

这个类需要由connection对象创建的,内部保存了从connection对象取来的pdo数据库连接。command类的定位是直接执行SQL,也提供bind参数的能力,它不再限制SQL是读还是写,这也是为什么Query类不直接使用connection的pdo连接执行读SQL而是把构造来的SQL交给command,因为command类才是负责执行所有SQL的合适角色,职责集中在Command对象是一个合理的设计。

根据这个认识,我们知道Command类可以直接执行裸SQL,读和写都是可以的。

ActiveQuery

之前的Query算一个调度者,它从用户收集查询的组成要素,交给QueryBuilder生成SQL,最后交给Command完成SQL的执行,拿回来的结果都是数组形式的一行一行的数据。

ActiveQuery则是在Query基础上(继承自Query),额外提供了ORM能力,主要包含2点:数据库行映射为对象(就是指ActiveRecord,也是一个model),以及表的关联关系。

我们知道Query的one和all都是返回关联数组形式的结果集,而ActiveRecord则覆盖了这两个方法,为每一行数据生成对应的activeRecord对象并把列值填充到对象里,这样就实现了数据库行和程序对象的自动映射,大概就是这种关系了。

 
标签: SQL Yii
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • Perl操作Mysql数据库 perl操作excel
    一. 安装DBI模块步骤1:从TOOLS栏目中下载DBI.zip,下载完后用winzip解开到一个temp目录,共有三个文件:ReadmeDBI.ppdDBI.tar.gz步骤2: 在DOS窗口下,temp目录中运行下面的DOS命令:ppm install DBI.ppd 如果提示无效命令,可在perl/bin目录下运行 二. 安装DBD
    02-09
  • 在OS X系统中配置Ruby on Rails使其可以访问Sql
    经过大半天的折腾,终于可以让RoR在OS X系统里访问Sql Server数据库了。这里记录一下操作的过程,免得以后忘了。第一步,安装FreeTDS从FreeTDS的官网上下载最新的稳定版的压缩包,然后,遵照这里的说明进行手工编译(好怀念微软的Setup.exe和*.msi啊),其中
    02-09
  • Nodejs+Express+Mysql实现简单用户管理增删改查
    Nodejs+Express+Mysql实现简单用户管理增删改查
     源码地址  https://github.com/king-y/NodeJs/tree/master/user目录结构  mysql.jsvar mysql = require('mysql');var pool = mysql.createPool({host : '127.0.0.1',user : 'root',password : '',database : 's79'});exports.que
    02-09
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
    PHP 使用 Swoole - TaskWorker 实现异步操作 My
    在一般的 Server 程序中都会有一些耗时的任务,比如:发送邮件、聊天服务器发送广播等。如果我们采用同步阻塞的防水去执行这些任务,那么这肯定会非常的慢。Swoole 的 TaskWorker 进程池可以用来执行一些异步的任务,而且不会影响接下来的任务,很适合处理以
    02-09
  • Mysql数据库一个小程序实现自动创建分表。
    每当跨月的时候也是系统出问题最多的时候,没有表和字段缺失是两个最常见的错误。为了解决这个问题,研究了一下mysql的 information_schema 表:information_schema这张数据表保存了MySQL服务器所有数据库的信息。如数据库名,数据库的表,表栏的数据类型与访
    02-09
  • Rust 连接 SQLite 数据库
    Rust 连接 SQLite 数据库
    使用 Rust 语言连接操作 SQLite 数据库,我使用 rusqlite 这个 crate。看例子:首先,使用 cargo 创建一个 Rust 项目,然后添加依赖 rusqlite: 来到 main.rs,其余所有的代码都写在这里。首先引入 rusqlite 相关的类型,并建立一个 Person struct:Person
    02-09
  • Rust 连接 PostgreSQL 数据库
    Rust 连接 PostgreSQL 数据库
    这次,我们使用 postgres 这个 crate 来连接和操作 PostgreSQL 数据库。创建好项目后,在 cargo.toml 里添加 postgres 的依赖: 首先,导入相关的类型,并创建一个 Person struct: 再创建 create_db 函数,用来创建数据库和表,它返回一个 Result,里面可
    02-09
  • Delphi中多线程下使用使用 UniDAC+MSSQL 需要注
    一般解决方法是在线程开始启用 CoInitialize(nil),线程结束调用 CoUninitialize 。如果你使用多种数据库连接,比如三层中经常切换到MSSQL和Oracle,我们只需在判断 TUniConnection 的连接前事件 OnBeforeConnect 写下如下代码:  [delphi] view plain co
    02-09
  • delphi10.3安装使用mySQL及遇到的问题(01)
    delphi10.3安装使用mySQL及遇到的问题(01)
    1】下载安装好mySQL环境2】FDConnection1的设置3】执行增删改SQL语句和查询Select语句4】客户端连接5]长文本类型,及SQLITE导出,导入到MySQL6】遇到过的问题及解决1】下载安装好mySQL环境,注意32位/64位。本篇为32位mysql32位下载链接: https://pan.baidu.c
    02-09
  • Delphi XE中使用dbExpress连接MySQL数据库疑难
    Delphi IDE中包含一个Data Explorer的组件,如下图所示:  该组件基于dbExpress(包含TSQLConnection、TSQLDataSet、TSQLQuery、TSQLStoredProc、TSQLTable、TsqlServerMethod、TSQLMonitor、TSimpleDataSet)。但是因为该组件只提供了各种数据库的抽象驱动
    02-09
点击排行