ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 数据操作教程 本章我们来了解一下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可以设置成 $keyword = "php"; findAll( array("title like :word", ":word" => '%'.$keyword.'%' ) ); PHP5.4 起可以使用短数组定义语法,用 [] 替代 array()。所以5.4之后可以使用更简洁优雅的方式来写$condition。 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.%"; 等同于 $condition = array('ip like :ip', ":ip" => "218.26.35.%" ); $obj->delete($condition); 2. OR逻辑复杂条件查询: SELECT * FROM students WHERE score > 90 AND ( classname = 'class1' OR classname = 'class2' ); 等同于 $condition = array("score > :score AND ( classname = :c1 OR classname = :c2 )", ":score" => 90, ":c1" => "class1", ":c2" => "class2", ); $obj->findAll($condition); **findAll()的$condition参数,实际上和find()、findCount()、delete()、update()、incr()、decr()的第一个参数$condition是完全一样的;这些方法的条件数组,都可以使用上述的两种模式的数组。** > 对比旧版的$condition字符串条件查询,新版的$condition已经不再支持纯粹的字符串查询,而是采用更安全、不需要手动escape的“字符串+绑定参数”组成的数组才能进行查询。 > **绑定参数是目前数据库编程避免SQL注入的最佳方法。** - $sort,字符串形式,指定查询结果的排序方式。 首先我们来看看,通常SQL语句中的排序是如何实现的,比如说留言本中需要按照时间先后排序(正序,就是ASC,反序DESC) SELECT * FROM spgb_gb ORDER BY post_time ASC // 正序,也就是时间小的排前面 SELECT * FROM spgb_gb ORDER BY post_time DESC // 反序,时间大的排前面 SELECT * FROM spgb_gb WHERE name = 'jake' ORDER BY post_time ASC, replay DESC // 查询留言者是jake的留言,按时间正序然后回复反序的方式排列(一般按回复内容的头字母排列) 而当我们使用find()/findAll()的时候,可以: $results = $gb->findAll(null, " post_time ASC "); // 条件为空,排序是时间正序 $results = $gb->findAll(null, " post_time DESC "); // 条件为空,排序是时间反序 $results = $gb->findAll(array( 'name' => 'jake' ), " post_time ASC, replay DESC "); // 条件为name=jake,排序是时间正序然后回复反序的方式排列 从上面可以看出,$sort参数就是直接使用ORDER BY的条件来排序的。即使有多个排序条件,也是可以和SQL语句一样使用的。 > 在$sort条件未设置的情况下,默认$sort是按主键的正序来进行查找。 - $fields,字符串形式,指定取得的结果字段集合。默认是“*”指的是取全部的字段结果。 在通常的数据库查找中,节省系统资源的一个方法,是限定查找返回的字段,可以减少PHP和数据库之间的数据流量,以达到优化程序和提高速度的目的。 SELECT gid, name, contents FROM spgb_gb SELECT spgb_gb.gid, spgb_gd.name, spgb_gb.contents FROM spgb_gb 以上两条SQL语句的相等的,而第二条SQL语句在返回的字段名称前,加上的表全名,这样做更为严谨。 而使用find()/findAll(),可以: $results = $gb->findAll(null, null, " gid, name, contents "); // 条件为空,排序为默认的主键ID排序,返回字段限制是gid, name, contents $results = $gb->findAll(null, null, " spgb_gb.gid, spgb_gd.name, spgb_gb.contents "); // 和上面相同 而在输出$results结果的时候,我们可以看到,find()/findAll()返回的结果仅有gid, name, contents $result = array( 0 => array( 'gid' => 12, 'name' => '小李', 'contents' => '我的留言', ), 1 => array( 'gid' => 13, 'name' => '小李', 'contents' => '我的第二条留言', ), ); 在使用$fields的时候,请注意:$fields一定要包括排序$sort的字段,比如按时间排序,那么$fields是务必要包含时间字段。当$sort 为空(默认)的时候,那么$field需要包含主键(因为默认$sort是按主键排序的) - $limit,字符串形式,指定取得结果的位移和数量。默认是取符合条件的全部纪录。$limit等同于LIMIT限定结果的语句。如“10, 20”指的是从第10条符合条件的纪录开始,取20条纪录。 **$limit一般是和$sort结合使用,如按留言时间反序,获取10条记录。** 举例: SELECT * FROM spgb_gb ORDER BY post_time DESC LIMIT 10 // 按时间反序,获取前面10条记录,相等于 LIMIT 0, 10(从0条开始,获取10条记录) SELECT * FROM spgb_gb ORDER BY post_time DESC LIMIT 30, 10 // 按时间反序,获取从30条开始的10条记录 而findAll()则是: $results = $gb->findAll(null, " post_time DESC ", "*", " 10 "); $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是新增纪录数组,数组键是字段名,值是数据值。如果在数组内没有对应的字段,那么会使用数据表默认值。 **示例** // 首先是准备新增的数据 // 表中的gid因为是自增量,所以没必要去赋值 // replay因为是可为空,并且刚留言也不会有回复,所以也可以不赋值 // 数组中的键是字段名称,值是数据 $newrow = array( // PHP的数组 'name' => 'jake', 'contents' => '这是我的第一个留言', 'post_time' => date('Y-m-d H:i:s'), 'post_ip' => $_SERVER['REMOTE_ADDRESS'], ); $gb = new Model("guestbook"); // 初始化留言本模型类 $gb->create($newrow); // 进行新增操作 **返回值**: create()新增成功则返回新增的自增量ID值,失败则抛出错误。 ### 四、删除纪录 delete() **用法**:delete($condition) **参数**: - $condition是删除纪录的条件,数组格式,条件和findAll()的$condition完全一样。 **示例** $condition = array('gid'=>13); // 构造条件 $gb = new Model("guestbook"); $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()的组合,不管是参数还是行为。 $condition = array('gid'=>12); $gb = new Model("guestbook"); $gb->update($condition, array('contents'=>'新信息')); **返回值**: update()和delete()一样,都是返回影响行数,也就是被修改了多少条件纪录。 ### 六、计算总数 findCount() **用法**:findCount($condition) **参数**: - $condition 和 findAll()等的$condition参数完全一样。 当我们需要计算数据表里面符合条件的纪录有多少条件,但又不想把全部纪录查出来的时候,那么findCount()就非常方便了。 findCount()方法主要用于计算符合$condition的记录数量。 // 我们来看看数据表中有多少条留言者是“jake”的留言 $condition = array( 'name' => 'jake' ); // 条件是同样的 $gb = new Model("guestbook"); // 初始化留言本模型类 $sum = $gb->findCount($condition); // 使用了findCount echo "jake总共留言了".$sum."条。"; **返回值**: 返回符合$condition记录的数量,如无任何符合条件的记录将返回 0。 ### 七、按字段增减 incr() / decr() 使用incr()和decr()可以很方便的进行数值字段的增加和减少。 如在计算页面访问量等操作中,只要一个incr()就可以实现数值增加。 **用法** incr($condition, $field, $optval = 1) decr($condition, $field, $optval = 1) 假设我们要为UID为10的博客页面增加一次的访问量: $blog = new Model("blog"); $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都是未经绑定参数的语句。