## 數據操作教程
本章我們來了解一下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. 多數據庫、主從庫配置