Db设计文档
Typecho中抛弃了繁琐的MVC构建方式,将所有的功能单纯地封装为一个模块(也就是上述的Widget),使其更加适合开源地并发开发模式.由于没有了Model层的存在,Widget必须直接与数据库联系.Db类的设计就是为了帮助你更快速的获取自己所需要的数据。Typecho的Db对象使用方法与Zend Framework中的Db对象很相似,我们参考了Zend_Db中的Select对象组织方法,但不保证完全兼容。它们之间有一些差别,造成这些差别的原因之一就是Zend为不同的操作提供了不同的对象,而Typecho的所有操作都由Typecho_Db_Query来封装成SQL语句的,它的好处是你能在不同的操作中使用统一的API。
初始化Db
在任何时候我们都可以通过如下方法获取一个实例化的Db对象。
//get方法是Typecho_Db的静态方法 $db = Typecho_Db::get();
但是在此之前,你必须利用Typecho_Db::set方法设置一个默认的且已经实例化好的db对象,db对象的实例化方法如下。
/** 定义数据库参数 */ $db = new Typecho_Db('Mysql', 'typecho_'); $db->addServer(array( 'host' => 'localhost', 'port' => '3306', 'user' => 'root', 'password' => '', 'database' => 'typecho', 'charset' => 'utf8' ), Typecho_Db::READ | Typecho_Db::WRITE); Typecho_Db::set($db);
它的构造函数第一个参数指定所用的适配器名称,第二个参数指定数据库表前缀,其中第二个参数可以不设置。当构造好一个db类以后,你可以将其看作一个数据库池,后面要做的就是往这个池中放入数据库连接。在上例中,我们为数据库对象加入了一个服务器,并为其指定行为为Typecho_Db::READ | Typecho_Db::WRITE,它表示可以读也可以写。
构建SQL语句
Typecho_Db内建的SQL语法构建器能够帮助你更容易地构建标准查询语句。
SELECT查询语句
select是我们最常用的查询方式,以下代码向您展示了如何使用Db类从posts表中取出所有数据.
//获取实例化对象 $db = Typecho_Db::get(); //获取查询语句对象 $select = $db->select()->from('posts'); //提交查询并获取结果 $result = $db->fetchAll($select);
查询指定字段
在以上查询代码中,我们从posts表中取出了所有数据,但同时也取出了所有字段,如果你只需要取出指定的几个字段,只需要对上述代码做出如下改进.
//重新构建select语句,在from方法中传递需要选择字段,并用半角逗号隔开 $select = $db->select('title', 'text', 'type')->from('posts');
可以看到,我们给每个字段加上了一个`标志,这主要是为了不同数据库兼容性的考虑,在后面将会详细讲述.
增加查询条件
大多数查询都需要增加查询条件,我们通过如下代码给我们的查询增加一个type = 'post'的条件.
$select = $db->select('title', 'text', 'type')->from('posts') ->where('type = ?', 'post');
如果需要增加多条条件限制,可以在后面继续调用where方法
$select = $db->select('title', 'text', 'type')->from('posts') ->where('type = ?', 'post') ->where('title = ?', 'hello');
它等效于`type` = 'post' AND `title` = 'hello'.你也可以用以下语句代替上述代码
$select = $db->select('title', 'text', 'type')->from('posts') ->where('type = ? AND title = ?', 'post', 'hello');
OR条件查询
使用where方法只能生成AND的并列条件查询,如果你需要OR条件查询,需要使用orWhere方法.我们通过下面的方法,给我们的查询增加`type` = 'post' OR `type` = 'page'的条件.
$select = $db->select('title', 'text', 'type')->from('posts') ->where('type = ?', 'post') ->orWhere('type = ?', 'page');
查询排序
在Typecho_Db中仅提供两种排序方法,非别为升序(Typecho_Db::SORT_ASC)和降序(Typecho_Db::SORT_DESC).使用order方法即可完成查询排序.
$select = $db->select() ->from('posts') ->where('type = ?', 'post') ->order('created', Typecho_Db::SORT_DESC); //降序排序
如果你不指定order方法的第二个参数,它将按照此数据库的默认方式排序,一般为升序.
指定查询范围
在Mysql中我们通常使用LIMIT语法来限制查询范围并实现翻页操作,但在其它数据库中则有所不同.不过使用Typecho_Db时你不需要关心这些语法,只需要关注你需要查询的范围即可.下面的代码展示了如何使用limit方法限制查询范围
$select = $db->select() ->from('posts') ->where('type = ?', 'post') ->limit(10); //仅取出10条记录
我们亦可以使用offset函数来指定查询范围的偏置值,也就是从第几条记录开始查询
$select = $db->select() ->from('posts') ->where('type = ?', 'post') ->offset(20) //从第20条记录开始取 ->limit(10);
在大多数情况下,我们使用范围限制是为了实现分页操作,我们在Typecho_Db中已经封装了分页操作,你只需要调用page方法即可实现分页,它的第一个参数是页数,第二个参数是每页的记录数.
$select = $db->select() ->from('posts') ->where('type = ?', 'post') ->page(10, 20); //按每页20条记录的方法取出第10页的记录
对引号的过滤
引号过滤是防范SQL注入的关键,你可以在上述代码中看到,Typecho的查询条件并没有直接写入语句,而是使用占位符的方式,使用参数传递来写入查询值.因此,使用占位符方式来构建查询语句,Typecho会在底层帮你处理引号,你自己不需要对此作出处理,而且也不要在字符型查询的外侧加上单引号,这种声明系统会自动处理.
联合查询
联合查询是SQL的常用语法,在Typecho中,您可以很方便的使用此类语句。下列代码展示了如何对两个表实现左连接
$select = $db->select() ->from('posts') ->join('category', 'posts.category_id = category.id', Typecho_Db::LEFT_JOIN) ->where('`type` = ?', 'post');
我们可以看到join方法一共有三个参数,第一个参数标明需要连接的表名,第二个参数是连接条件,第三个参数表示连接方法为左连接。其余的连接方式还有Typecho_Db::INNER_JOIN(内连接,如果第三个参数不填,则默认为内连接方式),Typecho_Db::OUTER_JOIN(外连接),Typecho_Db::LEFT_JOIN(左连接),Typecho_Db::RIGHT_JOIN(右连接)。
查看查询语句
有时候我们并不能保证自己所构建的查询语句是否正确,因此我们需要将查询语句输出。在typecho中,你可以很容易地查看sql语句。对于php 5.2以上版本,你可以直接用echo语句输出select对象,对于php 5.2以下版本,你需要调用select对象的toString方法输出。
$select = $db->select('posts') ->from('posts'); //如果版本大于php5.2 echo $select; //如果小于php5.2 echo $select->__toString(); //output: SELECT * FROM posts
INSERT语句
使用insert方法可以用于构建新增记录的查询语句。
插入一条记录
在typecho中,你不需要对插入的字段进行防注入过滤,我们已经在后端帮你完成了这个功能。以下代码揭示了如何构建一条标准的插入语句
$db = Typecho_Db::get(); $insert = $db->insert('post') ->rows(array('title' => 'example', 'content' => 'hello world')); //将构建好的sql执行, 如果你的主键id是自增型的还会返回insert id $insertId = $db->query($insert);
以上代码等价于
INSERT INTO post (title, content) VALUES ('example', 'hello world')
DELETE语句
delete方法用于删除数据库中的制定方法。
根据指定条件删除记录
我们通过在delete方法中使用我们在前面已经熟知的where语句来方便得进行条件删除。请看如下代码
$db = Typecho_Db::get(); $delete = $db->delete('post') ->where('title = ?', example); //将构建好的sql执行, 会自动返回已经删除的记录数 $deletedRows = $db->query($delete);
以上代码等价于
DELETE FROM post WHERE title = 'example'