数据操作教程

本章我们来了解一下sp框架的数据操作方法。

一、数据查找 findAll()

用法:findAll($conditions = array(), $sort = null, $fields = ‘*’, $limit = null)

参数

  • $condition,数组形式,查找纪录的条件。有两种方式:

    • 直接键对值的等于关系的AND条件,如array(“cid”=>12, “score”=>100),那么指代的查询是“ WHERE cid = 12 AND score = 100 ”。
    • 另一种是可以表示比等于和AND更为复杂的条件数组。该数组的[0]下标项,是查询的字符串条件,但是输入参数必须是绑定形式的;数组的其他键对值项,都是绑定的参数字段对应值。

      这种类型比较难理解,比如说我们需要模糊查找文章title带有“php”的文章,条件是: “WHERE title like ‘%php%’ ”。那么$condition可以设置成

      1. $keyword = "php";
      2. findAll(
      3. array("title like :word",
      4. ":word" => '%'.$keyword.'%'
      5. )
      6. );

      PHP5.4 起可以使用短数组定义语法,用 [] 替代 array()。所以5.4之后可以使用更简洁优雅的方式来写$condition。

      1. findAll(["title like :word",":word"=>"%".$keyword."%"]); // after 5.4

      $condition条件可以解决包括大于小于等于,or条件,like查询等条件的构造。这里多举两个例子:

      1. 假设我们要删除IP为218.26.35.*网段的纪录:

        DELETE * FROM records WHERE ip like “218.26.35.%”;

        等同于

        1. $condition = array('ip like :ip',
        2. ":ip" => "218.26.35.%"
        3. );
        4. $obj->delete($condition);
      2. OR逻辑复杂条件查询:

        SELECT * FROM students WHERE score > 90 AND ( classname = ‘class1’ OR classname = ‘class2’ );

        等同于

        1. $condition = array("score > :score AND ( classname = :c1 OR classname = :c2 )",
        2. ":score" => 90,
        3. ":c1" => "class1",
        4. ":c2" => "class2",
        5. );
        6. $obj->findAll($condition);

      findAll()的$condition参数,实际上和find()、findCount()、delete()、update()、incr()、decr()的第一个参数$condition是完全一样的;这些方法的条件数组,都可以使用上述的两种模式的数组。

      对比旧版的$condition字符串条件查询,新版的$condition已经不再支持纯粹的字符串查询,而是采用更安全、不需要手动escape的“字符串+绑定参数”组成的数组才能进行查询。

      绑定参数是目前数据库编程避免SQL注入的最佳方法。

  • $sort,字符串形式,指定查询结果的排序方式。

    首先我们来看看,通常SQL语句中的排序是如何实现的,比如说留言本中需要按照时间先后排序(正序,就是ASC,反序DESC)

    1. SELECT * FROM spgb_gb ORDER BY post_time ASC // 正序,也就是时间小的排前面
    2. SELECT * FROM spgb_gb ORDER BY post_time DESC // 反序,时间大的排前面
    3. SELECT * FROM spgb_gb WHERE name = 'jake' ORDER BY post_time ASC, replay DESC // 查询留言者是jake的留言,按时间正序然后回复反序的方式排列(一般按回复内容的头字母排列)

    而当我们使用find()/findAll()的时候,可以:

    1. $results = $gb->findAll(null, " post_time ASC "); // 条件为空,排序是时间正序
    2. $results = $gb->findAll(null, " post_time DESC "); // 条件为空,排序是时间反序
    3. $results = $gb->findAll(array( 'name' => 'jake' ), " post_time ASC, replay DESC "); // 条件为name=jake,排序是时间正序然后回复反序的方式排列

    从上面可以看出,$sort参数就是直接使用ORDER BY的条件来排序的。即使有多个排序条件,也是可以和SQL语句一样使用的。

    在$sort条件未设置的情况下,默认$sort是按主键的正序来进行查找。

  • $fields,字符串形式,指定取得的结果字段集合。默认是“*”指的是取全部的字段结果。

    在通常的数据库查找中,节省系统资源的一个方法,是限定查找返回的字段,可以减少PHP和数据库之间的数据流量,以达到优化程序和提高速度的目的。

    1. SELECT gid, name, contents FROM spgb_gb
    2. SELECT spgb_gb.gid, spgb_gd.name, spgb_gb.contents FROM spgb_gb

    以上两条SQL语句的相等的,而第二条SQL语句在返回的字段名称前,加上的表全名,这样做更为严谨。
    而使用find()/findAll(),可以:

    1. $results = $gb->findAll(null, null, " gid, name, contents "); // 条件为空,排序为默认的主键ID排序,返回字段限制是gid, name, contents
    2. $results = $gb->findAll(null, null, " spgb_gb.gid, spgb_gd.name, spgb_gb.contents "); // 和上面相同

    而在输出$results结果的时候,我们可以看到,find()/findAll()返回的结果仅有gid, name, contents

    1. $result = array(
    2. 0 => array(
    3. 'gid' => 12,
    4. 'name' => '小李',
    5. 'contents' => '我的留言',
    6. ),
    7. 1 => array(
    8. 'gid' => 13,
    9. 'name' => '小李',
    10. 'contents' => '我的第二条留言',
    11. ),
    12. );

    在使用$fields的时候,请注意:$fields一定要包括排序$sort的字段,比如按时间排序,那么$fields是务必要包含时间字段。当$sort 为空(默认)的时候,那么$field需要包含主键(因为默认$sort是按主键排序的)

  • $limit,字符串形式,指定取得结果的位移和数量。默认是取符合条件的全部纪录。$limit等同于LIMIT限定结果的语句。如“10, 20”指的是从第10条符合条件的纪录开始,取20条纪录。

    $limit一般是和$sort结合使用,如按留言时间反序,获取10条记录。

    举例:

    1. SELECT * FROM spgb_gb ORDER BY post_time DESC LIMIT 10 // 按时间反序,获取前面10条记录,相等于 LIMIT 0, 10(从0条开始,获取10条记录)
    2. SELECT * FROM spgb_gb ORDER BY post_time DESC LIMIT 30, 10 // 按时间反序,获取从30条开始的10条记录

    而findAll()则是:

    1. $results = $gb->findAll(null, " post_time DESC ", "*", " 10 ");
    2. $results = $gb->findAll(null, " post_time DESC ", "*", " 30, 10 ");

    新版sp框架的$limit可以是另一种形式,数组形态,可以支持自动分页计算。该数组有三个值,分别代表“当前页码”、“每页多少条纪录”、“分页显示范围”。

    比如说 $limit = array(5, 10, 10); 表示当前是取第5页的结果,每页显示10条纪录,分页显示范围是10。

    分页的具体介绍请参考手册相关文章。

    当$limit是数组,那么实际上findAll()会自动计算符合条件的纪录总数。

返回

findAll ()返回一个二维数组。第一层是各个符合条件的纪录,第二层是表字段对应纪录值的数组。

如果没有查询到结果,findAll()将返回一个空数组,可以通过empty()函数或者结果==false来判断是否有符合条件的结果。

二、查询一条纪录 find()

find()方法是findAll()的简便方法,它等同于:

  • findAll()设置了$limit=1,也就是findAll()只返回1条件记录。
  • 从结果中抽出第一个纪录的数组。(虽然就只有一个纪录)相当于取findAll()结果的[0]纪录数组。

find()有三个参数:$conditions, $sort, $fields,跟findAll()的前三个参数是完全相同的;而find()的返回结果是一维数组或者是空数组。

find()方法的好处是当有时候我们只需要查到符合条件的一条纪录,而不是纪录数组的第0条(findAll())。

比如说查询某ID的文章,我们只需要直接返回符合条件的准确纪录。这时候用find()就会直接方法一维数组,方便直接使用。

find()和findAll()的结果对比可以参考入门教程。

三、新增纪录 create()

用法:create($row)

参数

  • $row是新增纪录数组,数组键是字段名,值是数据值。如果在数组内没有对应的字段,那么会使用数据表默认值。

示例

  1. // 首先是准备新增的数据
  2. // 表中的gid因为是自增量,所以没必要去赋值
  3. // replay因为是可为空,并且刚留言也不会有回复,所以也可以不赋值
  4. // 数组中的键是字段名称,值是数据
  5. $newrow = array( // PHP的数组
  6. 'name' => 'jake',
  7. 'contents' => '这是我的第一个留言',
  8. 'post_time' => date('Y-m-d H:i:s'),
  9. 'post_ip' => $_SERVER['REMOTE_ADDRESS'],
  10. );
  11. $gb = new Model("guestbook"); // 初始化留言本模型类
  12. $gb->create($newrow); // 进行新增操作

返回值

create()新增成功则返回新增的自增量ID值,失败则抛出错误。

四、删除纪录 delete()

用法:delete($condition)

参数

  • $condition是删除纪录的条件,数组格式,条件和findAll()的$condition完全一样。

示例

  1. $condition = array('gid'=>13); // 构造条件
  2. $gb = new Model("guestbook");
  3. $gb->delete($condition);

返回值

delete()返回影响行数。所谓影响行数指的是修改或删除数据库纪录时,被修改或删除的纪录行数是多少。比如说上面的代码里面,如果gid = 13的纪录有两条,那么delete()后返回的结果是2。

如果delete()返回0,那么只是代表符合$condition条件的纪录为0,所以delete操作虽然已经正常执行,但是没有影响到任何一行纪录。

注意这里跟旧版完全不一样,旧版框架的delete和update都只是返回true/false。

新版框架返回影响行数,让我们可以更方便判断:修改/删除了多少条纪录。

五、修改纪录 update()

用法:update($condition, $row)

参数

  • $condition是修改纪录的条件,数组格式,条件和findAll()的$condition完全一样。
  • $row是待修改的新值数组,数组键是字段名,值是数据值。仅有$row里面有的字段才会被更新。

update()方法很像是delete() + create()的组合,不管是参数还是行为。

  1. $condition = array('gid'=>12);
  2. $gb = new Model("guestbook");
  3. $gb->update($condition, array('contents'=>'新信息'));

返回值

update()和delete()一样,都是返回影响行数,也就是被修改了多少条件纪录。

六、计算总数 findCount()

用法:findCount($condition)

参数

  • $condition 和 findAll()等的$condition参数完全一样。

当我们需要计算数据表里面符合条件的纪录有多少条件,但又不想把全部纪录查出来的时候,那么findCount()就非常方便了。

findCount()方法主要用于计算符合$condition的记录数量。

  1. // 我们来看看数据表中有多少条留言者是“jake”的留言
  2. $condition = array( 'name' => 'jake' ); // 条件是同样的
  3. $gb = new Model("guestbook"); // 初始化留言本模型类
  4. $sum = $gb->findCount($condition); // 使用了findCount
  5. echo "jake总共留言了".$sum."条。";

返回值

返回符合$condition记录的数量,如无任何符合条件的记录将返回 0。

七、按字段增减 incr() / decr()

使用incr()和decr()可以很方便的进行数值字段的增加和减少。

如在计算页面访问量等操作中,只要一个incr()就可以实现数值增加。

用法

incr($condition, $field, $optval = 1)

decr($condition, $field, $optval = 1)

假设我们要为UID为10的博客页面增加一次的访问量:

  1. $blog = new Model("blog");
  2. $blog->incr(array('uid'=>10), 'click');

decr()的使用同样简单,也是decr(条件, ‘字段名’)。

请注意:

  • incr()和decr()的参数$condition(条件),和find()/findAll()等方法的$condition一样。
  • incr()和decr()的参数$field(字段),该字段类型务必是数值类型。
  • 第三个参数$optval默认是1,如果要一次增加2或者更多的值,就可以设置$optval。

八、输出执行SQL供调试 dumpSql()

dumpSql()方法可以收集当前模型类执行过的全部SQL语句,返回一个包含了这些SQL语句的数组。

通常我们开发中可以使用dumpSql()来看看SQL语句正确与否。

因为绑定参数执行SQL的缘故,所以一般返回的SQL都是未经绑定参数的语句。