_一花一世界,
一沙一天国,
君掌盛无边,
刹那含永劫。_
_-- 《天真的预兆》_
##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:接口文档参考模板