====== Db设计文档 ====== Typecho中抛弃了繁琐的MVC构建方式,将所有的功能单纯地封装为一个模块(也就是上述的Widget),使其更加适合开源地并发开发模式.由于没有了Model层的存在,Widget必须直接与数据库联系.Db类的设计就是为了帮助你更快速的获取自己所需要的数据。Typecho的Db对象使用方法与[[http://framework.zend.com|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' ==== UPDATE语句 ====