本章我们首先从ThinkPHP5.0的数据库访问层架构设计原理开始,然后熟悉下数据库的配置,并掌握如何进行基础的查询操作,并简单介绍了分布式、存储过程及事务,学习内容主要包括:
- 数据库架构设计
- 数据库配置
- 如何开始查询
- 使用参数绑定
- 查询返回值
- 动态连接数据库
- 分布式支持
- 存储过程调用
- 数据库事务
- 总结
数据库架构设计
使用框架开发应用,一般不需要直接操作数据库,而是通过框架封装好的数据库中间层对数据库进行操作。这样的好处主要有两个:一是简化数据库操作,二是做到跨数据库的一致性。这种设计的中间层通常称之为数据库访问抽象层,简称数据访问层(DAL),ThinkPHP5的数据访问层是基于PHP内置的PDO对象实现。一般抽象层本身并不直接操作数据库,而是通过驱动来实现具体的数据库操作。
ThinkPHP5.0的数据库设计相比之前版本更加合理,数据访问层划分的更细化,把数据访问对象分成了连接器、查询器、生成器等多个对象,并通过数据库访问入口类统一调用,分工更明确,各司其职,欲知详情且听我慢慢道来。
ThinkPHP数据访问层设计示意图:
5.1版本的架构略微进行了一些调整,变成:
数据库入口类Db
平常我们的数据库操作使用的类库一般都是数据库的入口类thinkDb。这个类非常的简单,主要就是一个connect方法,根据数据库配置参数连接数据库(注意这里的连接并非真正的连接数据库,只是做好了随时连接的准备工作,只有在实际查询的时候才会真正去连接数据库,是一种惰性连接)并获取到数据库连接对象的实例。
Db类都是静态方法调用,但看起来这个类啥都没实现,那是怎么操作数据库的呢,其实就是封装了数据库操作方法的静态调用(利用__callStatic方法),下面是代码实现:
// 调用驱动类的方法public static function __callStatic($method, $params){ // 自动初始化数据库 return call_user_func_array([self::connect(), $method], $params);}
理论上来说,框架并不依赖Db类,该类的存在只是为了简化数据库抽象层的操作而提供的一个工厂类,否则你就需要单独实例化不同的数据库连接类。因此,看似可有可无的Db类就成了数据访问层实现的点睛之笔了。
所有的数据库操作都是经过Db类调用,并且Db类是一个静态类,但Db类自身只有一个公共方法connect。
连接器类Connection
顾名思义,连接类的作用就是连接数据库,也称为连接器。我们知道,不同的数据库的连接方式和参数都是不同的,连接类就是要解决这个差异问题。
数据库入口类里面实例化的类其实就是对应数据库的连接类,连接类的基类是thinkdbConnection。例如,需要连接Mysql数据库的话,就必须定义一个Mysql连接类(内置由thinkdbconnectorMysql类实现,继承了thinkdbConnection类),当然具体的连接类名没有固定的规范(例如,MongoDb的连接类就是thinkmongoConnection)。如果某个数据库的连接扩展类没有继承thinkdbConnection,那就意味着所有的数据库底层操作有可能被接管,在个别特殊的数据库的扩展中就有类似的实现,例如MongoDb数据库扩展。
数据库连接都是惰性的,只有最终执行SQL的时候才会进行连接。
连接器是数据访问层的基础,基于PHP本身的PDO实现(如果你还不了解PDO,请参考PHP官方手册中PDO部分,不在本书的讨论范畴),连接类的主要作用就是连接具体的数据库,以及完成基本的数据库底层操作,包括对分布式、存储过程和事务的完善处理。而更多的数据操作则交由查询类完成。
框架内置的连接类包括:
数据库 连接类 Mysql thinkdbconnectorMysql Pgsql thinkdbconnectorPgsql Sqlite thinkdbconnectorSqlite Sqlsrv thinkdbconnectorSqlsrv
如果是仅仅使用原生SQL查询的话,只需要使用连接类就可以了(通过调用Db类完成)
连接器类的作用小结:
- 连接数据库;
- 获取数据表和字段信息;
- 基础查询(原生查询);
- 事务支持;
- 分布式支持;
查询器类Query
除了基础的原生查询可以在连接类完成之外,其它的查询操作都是调用查询类的方法,查询类内完成了数据访问层最重要的工作,衔接了连接类和生成类,统一了数据库的查询用法,所以查询类是不需要单独驱动配合的,我们也称之为查询器。无论采用什么数据库,我们的查询方式是统一的,因为数据访问层核心只有一个唯一的查询类:thinkdbQuery。
Query类封装了所有的数据库CURD方法的优雅实现,包括链式方法及各种查询,并自动使用了PDO参数绑定(参数自动绑定是在生成器类解析生成SQL时完成),最大程度地保护你的程序避免受数据库注入攻击,查询操作会调用生成类生成对应数据库的SQL语句,然后再调用连接类提供的底层原生查询方法执行最终的数据库查询操作。
所有的数据库查询都使用了PDO的预处理和参数绑定机制。你所看到的大部分数据库方法都来自于查询类而并非Db类,这一点很关键,也就是说虽然我们始终使用Db类操作数据库,而实际上大部分方法都是由查询器类提供的方法。
生成器类Builder
生成类的作用是接收Query类的所有查询参数,并负责解析生成对应数据库的原生SQL语法,然后返回给Query类进行后续的处理(包括交给连接类进行SQL执行和返回结果处理),也称为(语法)生成器。生成类的作用其实就是解决不同的数据库查询语法之间的差异。查询类实现了统一的查询接口,而生成类负责数据库底层的查询对接。
生成类一般不需要自己调用,而是由查询类自动调用的。也可以这么理解,生成类和查询类是一体的,事实上它们合起来就是通常我们所说的查询构造器(因为实际的查询操作还是在连接器中执行的)。
通常每一个数据库连接类都会对应一个生成类,框架内置的生成类包括:
数据库 生成类 Mysql thinkdbbuilderMysql Pgsql thinkdbbuilderPgsql Sqlite thinkdbbuilderSqlite Sqlsrv thinkdbbuilderSqlsrv
这些生成类都继承了核心提供的生成器基类thinkdbBuilder,每个生成器类只需要提供差异部分的实现。
数据库配置
数据库的配置参数有很大的学问,也是你掌握数据库操作的基础,主要用于数据库的连接以及查询的相关设置。
数据库的配置参数用于连接类的