## 数据操作教程
本章我们来了解一下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都是未经绑定参数的语句。
- 自述
- 一、入门教程
- 1. 开始使用SpeedPHP
- 2. Hello World
- 3. 理解MVC
- 4. 制作留言本
- 5. 数据操作及Ajax
- 二、框架概述
- 1. 特色
- 2. 版权及开源协议
- 3. 开发环境
- 4. 编码版本
- 5. SAE平台使用
- 三、开发指南
- 1. 开发流程
- 2. 架构及扩展
- 3. 程序目录结构
- 4. 命名建议
- 5. 安全建议
- 6. 用户自定义
- 7. 模块modules
- 四、访问交互
- 1. 表单提交及数据获取
- 2. session/cookie的使用
- 3. 伪静态及URL跳转
- 4. 使用frameset
- 5. 模板引擎特性和使用方法
- 五、数据操作
- 1. 建立数据模型类
- 2. 数据操作教程
- 3. 分页
- 4. SQL支持及关联实现
- 5. 多数据库、主从库配置