_一花一世界,
一沙一天國,
君掌盛無邊,
剎那含永劫。_
_-- 《天真的預兆》_
##1.20.1 前提
為了讓大家更為明確數據庫NotORM的使用,我們假設有以下數據庫表:
```
-- ----------------------------
-- Table structure for `tbl_user`
-- ----------------------------
DROP TABLE IF EXISTS `tbl_user`;
CREATE TABLE `tbl_user` (
`id` int(11) NOT NULL,
`name` varchar(45) DEFAULT NULL,
`age` int(3) DEFAULT NULL,
`note` varchar(45) DEFAULT NULL,
`create_date` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tbl_user
-- ----------------------------
INSERT INTO `tbl_user` VALUES ('1', 'dogstar', '18', 'oschina', '2015-12-01 09:42:31');
INSERT INTO `tbl_user` VALUES ('2', 'Tom', '21', 'USA', '2015-12-08 09:42:38');
INSERT INTO `tbl_user` VALUES ('3', 'King', '100', 'game', '2015-12-23 09:42:42');
```
并且,假設我們已獲得了tbl_user表對應的notorm實例$user,此NotORM表實例可從兩種方式獲得:
+ 1、使用原生態的notorm,即:$user = DI()->notorm->user
+ 2、使用PhalApi_Model_NotORM基類的方式,即:$user = $this->getORM(),如:
```
<?php
class Model_User extends PhalApi_Model_NotORM {
protected function getTableName($id) {
return 'user';
}
public function doSth() {
$user = $this->getORM(); //獲取NotORM表實例
}
}
```
##寫在前面的話
NotORM的實例是有內部狀態的,因為在開發過程中,需要特別注意何時需要保留狀態(使用同一個實例)、何時不需要保留狀態。即:
保留狀態的寫法:
```
$user = $notorm->user; //獲取一個新的實例
$user->where('age > ?', 18);
$user->where('name LIKE ?', '%dog%'); //相當于age > 18 AND name LIKE '%dog%'
```
不保留狀態的寫法:
```
$user = $notorm->user; //獲取一個新的實例
$user->where('age > ?', 18);
$user = $notorm->user; //重新獲取新的實例
$user->where('name LIKE ?', '%dog%'); //此時只有 name LIKE '%dog%'
```
關于這兩者的使用場景,下面在進行說明時會特別提及。
下面,就讓我們結合實例來嘗試一下數據庫的操作吧!
##1.20.2 基本操作
###(1)SELECT
####單個字段:
```
// SELECT id FROM `tbl_user`
$user->select('id')
```
####多個字段獲取:
```
// SELECT id, name, age FROM `tbl_user`
$user->select('id, name, age')
```
####字段別名獲取:
```
// SELECT id, name, MAX(age) AS max_age FROM `tbl_user`
$user->select('id, name, MAX(age) AS max_age')
```
####全部字段(缺省)獲取:
```
// SELECT * FROM `tbl_user`
$user->select('*')
```
###(2)WHERE
####單個字段查詢:
```
// WHERE id = 1
$user->where('id', 1)
$user->where('id = ?', 1)
$user->where(array('id', 1))
```
####多個字段查詢:
```
// WHERE id > 1 AND age > 18
$user->where('id > ?', 1)->where('age > ?', 18)
$user->and('id > ?', 1)->and('age > ?', 18)
$user->where('id > ? AND age > ?', 1, 18)
$user->where(array('id > ?' => 1, 'age > ?' => 10))
// WHERE name = 'dogstar' AND age = 18
$user->where(array('name' => 'dogstar', 'age' => 18))
// WHERE name = 'dogstar' OR age = 18
$user->or('name', 'dogstar')->or('age', 18)
```
####IN查詢:
```
// WHERE id IN (1, 2, 3)
$user->where('id', array(1, 2, 3))
// WHERE id NOT IN (1, 2, 3)
$user->where('NOT id', array(1, 2, 3))
// WHERE (id, age) IN ((1, 18), (2, 20))
$user->where('(id, age)', array(array(1, 18), array(2, 20)))
```
####模糊匹配查詢:
```
// WHERE name LIKE '%dog%'
$user->where('name LIKE ?', '%dog%')
```
####NULL判斷查詢:
```
// WHERE (name IS NULL)
$user->where('name', null)
```
###(3)ORDER BY
####單個字段排序:
```
// ORDER BY age
$user->order('age')
// ORDER BY age DESC
$user->order('age DESC')
```
####多個字段排序:
```
// ORDER BY id, age DESC
$user->order('id')->order('age DESC')
$user->order('id, age DESC')
```
###(4)LIMIT
####按數量限制:
```
// LIMIT 10
$user->limit(10)
```
####按數量和偏移量限制(請注意:先偏移量、再數量):
```
// LIMIT 2,10
$user->limit(2, 10)
```
###(5)GROUP BY和HAVING
####不帶HAVING:
```
// GROUP BY note
$user->group('note')
```
####帶HAVING:
```
// GROUP BY note HAVING age > 10
$user->group('note', 'age > 10')
```
##1.20.3 CURD之查詢類(Retrieve)
操作|說明|示例|備注|是否PhalApi新增
---|---|---|---|---
fetch()|循環獲取每一行|while($row = $user->fetch()) { //... }||否
fetchOne()|只獲取第一行|$row = $user->where('id', 1)->fetchOne();|等效于fetchRow()|是
fetchRow()|只獲取第一行|$row = $user->where('id', 1)->fetchRow();|等效于fetchOne()|是
fetchPairs()|獲取鍵值對|$row = $user->fetchPairs('id', 'name');|第二個參數為空時,可取多個值,并且多條紀錄|否
fetchAll()|獲取全部的行|$rows = $user->where('id', array(1, 2, 3))->fetchAll();|等效于fetchRows()|是
fetchRows()|獲取全部的行|$rows = $user->where('id', array(1, 2, 3))->fetchRows();|等效于fetchAll()|是
queryAll()|復雜查詢下獲取全部的行,默認下以主鍵為下標|$rows = $user->queryAll($sql, $parmas);|等效于queryRows()|是
queryRows()|復雜查詢下獲取全部的行,默認下以主鍵為下標|$rows = $user->queryRows($sql, $parmas);|等效于queryAll()|是
count()|查詢總數|$total = $user->count('id');|第一參數可省略|否
min()|取最小值|$minId = $user->min('id');||否
max()|取最大值|$maxId = $user->max('id');||否
sum()|計算總和|$sum = $user->sum('age');||否
####循環獲取每一行(多個字段):
```
// SELECT id, name FROM tbl_user WHERE (age > 18);
$user = $notorm->user->select('id, name')->where('age > 18');
while($row = $user->fetch()) {
var_dump($row);
}
// 輸出
array(2) {
["id"]=>
string(1) "2"
["name"]=>
string(3) "Tom"
}
array(2) {
["id"]=>
string(1) "3"
["name"]=>
string(4) "King"
}
```
####循環獲取每一行(單個字段):
```
// SELECT id, name FROM tbl_user WHERE (age > 18);
$user = $notorm->user->select('id, name')->where('age > 18');
while($row = $user->fetch('name')) { // 指定獲取name這列,但此字段須在select里
var_dump($row);
}
// 輸出
string(3) "Tom"
string(4) "King"
```
####循環獲取每一行(錯誤的用法,注意!會死循環):
```
while($row = $notorm->user->select('id, name')->where('age > 18')->fetch('name')) {
var_dump($row);
}
```
####只獲取第一行(多個字段):
```
// SELECT id, name FROM tbl_user WHERE (age > 18) LIMIT 1;
$rs = $user->select('id, name')->where('age > 18')->fetchOne(); //等同fetchRow()
var_dump($rs);
// 輸出
array(2) {
["id"]=>
string(1) "2"
["name"]=>
string(3) "Tom"
}
```
####只獲取第一行(單個字段):
```
var_dump($user->fetchOne('name')); // 輸出 string(3) "Tom"
var_dump($user->fetchRow('name')); // 等同輸出 string(3) "Tom"
```
####獲取鍵值對(多個字段):
```
// SELECT id, name, age FROM tbl_user LIMIT 2;
$rs = $user->select('name, age')->limit(2)->fetchPairs('id'); //指定以ID為KEY
var_dump($rs);
// 輸出
array(2) {
[1]=>
array(3) {
["id"]=>
string(1) "1"
["name"]=>
string(7) "dogstar"
["age"]=>
string(2) "18"
}
[2]=>
array(3) {
["id"]=>
string(1) "2"
["name"]=>
string(3) "Tom"
["age"]=>
string(2) "21"
}
}
```
####獲取鍵值對(單個字段):
```
// SELECT id, name FROM tbl_user LIMIT 2
var_dump($user->limit(2)->fetchPairs('id', 'name')); //通過第二個參數,指定VALUE的列
// 輸出
array(2) {
[1]=>
string(7) "dogstar"
[2]=>
string(3) "Tom"
}
```
####獲取全部的行:
```
// SELECT * FROM tbl_user
var_dump($user->fetchAll()); //全部表數據輸出,輸出結果略,相當于$user->fetchRows()
```
####復雜查詢下獲取全部的行(1.3.1及以前版本默認下以主鍵為下標,1.3.1以后的版本則默認采用數組方式):
```
// SELECT name FROM tbl_user WHERE age > :age LIMIT 1
$sql = 'SELECT name FROM tbl_user WHERE age > :age LIMIT 1';
$params = array(':age' => 18);
$rs = $user->queryAll($sql, $params);
var_dump($rs);
// 輸出
array(1) {
[0]=>
array(1) {
["name"]=>
string(3) "Tom"
}
}
// 也可以這樣。。。
$sql = 'SELECT name FROM tbl_user WHERE age > ? LIMIT 1'; //使用問號表示變量
$params = array(18);
$rs = $user->queryRows($sql, $params); //使用queryRows()別名
var_dump($rs);
```
請注意:使用上面這種方式進行查詢,需要手動填寫完整的表名字,并且需要通過某個表的實例來運行。
####取最小值:
```
// SELECT MIN(age) FROM tbl_user
var_dump($user->min('age'));
// 輸出
string(2) "18"
```
####取最大值:
```
// SELECT MAX(age) FROM tbl_user
var_dump($user->max('age'));
// 輸出
string(3) "100"
```
####計算總和:
```
// SELECT SUM(age) FROM tbl_user
var_dump($user->sum('age'));
// 輸出
string(3) "139"
```
##1.20.4 CURD之插入類(Create)
操作|說明|示例|備注|是否PhalApi新增
---|---|---|---|---
insert()|插入數據|$user->insert($data);|原生態操作需要再調用insert_id()獲取插入的ID|否
insert_multi()|批量插入|$user->insert_multi($rows);|可批量插入|否
insert_update()|插入/更新|接口簽名:insert_update(array $unique, array $insert, array $update = array()|不存時插入,存在時更新|否
####插入數據
```
// INSERT INTO tbl_user (id, name, age, note) VALUES (4, 'PhalApi', 1, 'framework')
$data = array('id' => 4, 'name' => 'PhalApi', 'age' => 1, 'note' => 'framework');
$user->insert($data);
$id = $user->insert_id(); //必須是同一個實例,方能獲取到新插入的行ID,且表必須設置了自增
var_dump($id); //新增的ID
//使用Model的寫法
$model = new Model_User();
var_dump($model->insert($data)); //輸出新增的ID
```
####批量插入:
```
// INSERT INTO tbl_user (name, age, note) VALUES ('A君', 12, 'AA'), ('B君', 14, 'BB'), ('C君', 16, 'CC')
$rows = array(
array('name' => 'A君', 'age' => 12, 'note' => 'AA'),
array('name' => 'B君', 'age' => 14, 'note' => 'BB'),
array('name' => 'C君', 'age' => 16, 'note' => 'CC'),
);
$rs = $user->insert_multi($rows);
var_dump($rs);
// 輸出
int(3) //成功插入的條數
```
####插入/更新:
```
// INSERT INTO tbl_user (id, name, age, note) VALUES (8, 'PhalApi', 1, 'framework') ON DUPLICATE KEY UPDATE age = 2
$unique = array('id' => 8);
$insert = array('id' => 8, 'name' => 'PhalApi', 'age' => 1, 'note' => 'framework');
$update = array('age' => 2);
$rs = $user->insert_update($unique, $insert, $update);
var_dump($rs); //輸出影響的行數
```
##1.20.5 CURD之更新類(Update)
操作|說明|示例|備注|是否PhalApi新增
---|---|---|---|---
update()|更新數據|$user->where('id', 1)->update($data);|更新異常時返回fals,數據無變化時返回0,成功更新返回1|否
####更新數據:
```
// UPDATE tbl_user SET age = 2 WHERE (name = 'PhalApi');
$data = array('age' => 2);
$rs = $user->where('name', 'PhalApi')->update($data);
var_dump($rs);
// 輸出
int(1) //正常影響的行數
int(0) //無更新,或者數據沒變化
boolean(false) //更新異常、失敗
```
####更新數據(+1):
```
// UPDATE tbl_user SET age = age + 1 WHERE (name = 'PhalApi')
$rs = $user->where('name', 'PhalApi')->update(array('age' => new NotORM_Literal("age + 1")));
var_dump($rs); //輸出影響的行數
```
##1.20.6 CURD之刪除類(Delete)
操作|說明|示例|備注|是否PhalApi新增
---|---|---|---|---
delete()|刪除|$user->where('id', 1)->delete();|禁止無where條件的刪除操作|否
按條件刪除,返回影響的行數:
```
// DELETE FROM tbl_user WHERE (id = 404);
$user->where('id', 404)->delete();
```
** 注意:** 如果是全表刪除,框架將會禁止,并拋出異常。如:
```
// Exception: sorry, you can not delete the whole table
$user->delete();
```
##參考
更多請參考 [NotORM官網接口說明](http://www.notorm.com/#api)
- 歡迎使用PhalApi!
- 接口,從簡單開始!
- [1.1]-下載與安裝
- [1.2]-創建一個自己的項目
- [1.3]-在線體驗
- [1.4]-文檔、幫助和官網
- [1.10]-對PhalApi框架的抉擇
- [1.11]-快速入門(backup)
- [1.12]-參數規則:接口參數規則配置
- [1.13]-統一的接口請求方式:_sevice=XXX.XXX
- [1.14]-統一的返回格式和結構:ret-data-msg
- [1.15]-數據庫操作:基于NotORM的使用及優化
- [1.16]-配置讀取:內外網環境配置的完美切換
- [1.17]-日記紀錄:簡化版的日記接口
- [1.18]-快速函數:人性化的關懷
- [1.19]-DI服務速查:各資源服務一覽表
- [1.20]-DB操作:數據庫基本操作速查
- [1.21]-類的自動加載:遵循PEAR包的命名規范
- [1.22]-簽名驗證:自定義簽名規則
- [1.23]-請求和響應:GET和POST兩者皆可得及超越JSON格式返回
- [1.24]-緩存策略:更靈活地可配置化的多級緩存
- [1.25]-國際化翻譯:為走向國際化提前做好翻譯準備
- [1.26]-數據安全:數據對稱加密方案
- [1.27]-精益開發:更富表現力的Model層和重量級數據獲取的應對方案
- [1.28]-COOKIE:對COOKIE原生態的支持及記憶加密升級版
- [1.29]-開放與封閉:多入口和統一初始化
- [1.30]-保持的力量:接口開發最佳實踐
- [1.31]-新型計劃任務:以接口形式實現的計劃任務
- [2.11]-核心思想:DI依賴注入-讓資源更可控
- [2.12]-海量數據:可配置的分庫分表
- [2.13]-接口調試:在線SQL語句查看與性能優化
- [2.14]-測試驅動開發:意圖導向編程下的接口開發
- [2.15]-演進:新型計劃任務續篇
- [2.16]-領域驅動設計:應對復雜領域業務的Domain層
- [2.17]-微服務:Api接口服務層
- [2.18]-定制化:資源服務的再實現
- [2.19]-擴展庫:可重用的擴展類庫
- [2.20]-約定編程:架構明顯的編程風格
- [2.21]-服務器統一部署方案簡明版:CentOs---Nginx---php-fpm---MySql-[--Memcached]
- [2.22]-更多工具:精益項目和團隊建設
- [3.1]-擴展類庫:微信開發
- [3.2]-擴展類庫:代理模式下phprpc協議的輕松支持
- [3.3]-擴展類庫:基于PHPMailer的郵件發送
- [3.4]-擴展類庫:優酷開放平臺接口調用
- [3.5]-擴展類庫:七牛云存儲接口調用
- [3.6]-擴展類庫:新型計劃任務
- [3.8]-擴展類庫:用戶、會話和第三方登錄集成
- [3.9]-擴展類庫:swoole支持下的長鏈接和異步任務實現
- [3.11]-擴展類庫:基于FastRoute的快速路由
- [4.2]-開發實戰2:模擬優酷開放平臺接口項目開發
- [4.3]-開發實戰3:一個簡單的小型項目開發(奔跑吧兄弟投票活動)
- [5.1]-架構與思想:PhalApi核心設計和思想解讀
- [5.2]-雜談:扯一些PhalApi的前世和今生
- [5.3]-框架總結:術語表和PHP開發建議
- [5.4]-許可
- [5.5]-聯系和加入我們
- [5.6]-更新日記
- [5.8]-致框架貢獻者:加入PhalApi開源指南
- [6.1]-基于接口查詢語言的SDK包
- [6.2]-SDK包(JAVA版)
- [6.3]-SDK包(PHP版)
- [6.4]-SDK包(Objective-C版)
- [6.5]-SDK包(javascript版)
- [6.6]-SDK包(Ruby版)
- [8.1]-PhalApi視頻教程
- 附錄1:接口文檔參考模板