筋斗云接口编程 / 常用操作(三)
来源:互联网 发布:在淘宝买的机票怎么取 编辑:程序博客网 时间:2024/06/04 17:48
数据库操作
数据库连接一开始是通过tool/init.php在线配置的,或直接手改文件 php/conf.user.php 文件的相关配置如:
putenv("P_DB=localhost/jdcloud");putenv("P_DBCRED=test:test123");
如果想稍稍隐蔽一下登录账号,也可以用base64编码,如:
putenv("P_DBCRED=ZGVtbzpkZW1vMTIz");
数据库查询的常用函数是queryOne
和queryAll
,用来执行SELECT查询。
queryOne只返回首行数据,特别地,如果返回行中只有一列,则直接返回首行首列值:
// 查到数据时,返回首行 [$id, $dscr],例如 [100, "用户100"]// 没有查到数据时,返回 false$rv = queryOne("SELECT id, dscr FROM Ordr WHERE userId={$uid}");list($id,$dscr) = $rv;// 查到数据时,由于SELECT语句只有一个字段id,因而返回值即是$id,例如返回100$rv = queryOne("SELECT id FROM Ordr WHERE userId={$uid}");$id = $rv;
如果字段较多,常加参数PDO::FETCH_ASSOC
要求返回关联数组以增加可读性:
// 操作成功时,返回关联数组,例如 ["id" => 100, "dscr" => "用户100"]$rv = queryOne("SELECT id, dscr FROM Ordr WHERE userId={$uid}", PDO::FETCH_ASSOC);
如果要查询所有行的数据,可以用queryAll
函数:
// 有数据时,返回二维数组 [[$id, $dscr], ...]// 没有数据时,返回空数组 [],而不是false$rv = queryAll("SELECT id, dscr FROM Ordr WHERE userId={$uid}");
执行非查询语句可以用包装函数execOne
如:
execOne("DELETE ...");execOne("UPDATE ...");execOne("INSERT INTO ...");
对于insert语句,可以取到执行后得到的新id值:
$newId = execOne("INSERT INTO ...", true);
[防备SQL注入]
要特别注意的是,所有外部传入的字符串参数都不应直接用来拼接SQL语句,
下面登录接口的实现就包含一个典型的SQL注入漏洞:
$uname = mparam("uname");$pwd = mparam("pwd");$id = queryOne("SELECT id FROM User WHERE uname='$uname' AND pwd='$pwd'");if ($id === false) throw new MyException(E_AUTHFAIL, "bad uname/pwd", "用户名或密码错误");// 登录成功$_SESSION["uid"] = $id;
如果黑客精心准备了参数 uname=a&pwd=a' or 1=1
,这样SQL语句将是
SELECT id FROM User WHERE uname='a' AND pwd='a' or 1=1
总可以查询出结果,于是必能登录成功。
修复方式很简单,可以用Q函数进行转义:
$sql = sprintf("SELECT id FROM User WHERE uname=%s AND pwd=%s", Q($uname), Q($pwd));$id = queryOne($sql);
因为很常用,所以使用了一个超级简单的名字叫Q(quote),它一般的实现就是:
global $DBH;$DBH->quote($str);
[SQL编译优化]
全局变量$DBH
是默认的数据库连接对象,即PDO对象,在程序中也可以直接使用,比如要插入大量数据,为优化性能,可以先对SQL语句进行编译(prepare)后再执行:
global $DBH;$tm = date(FMT_DT);$sth = $DBH->prepare("INSERT INTO ApiLog (tm, addr) VALUES ('$tm', ?)");foreach ($addrList as $addr) { $sth->execute([$addr]);}
上面用到的常量FMT_DT是框架定义的标准日期格式,常用于格式化日期字段传到数据库。
[支持数据库事务]
假如有一个用户用帐户余额给订单付款的接口,先更新订单状态,再更新用户帐户余额:
function api_payOrder(){ execOne("UPDATE Ordr SET status='已付款'..."); ... execOne("UPDATE User SET balance=..."); ...}
在更新之后,假如因故抛出了异常返回,订单状态或用户余额会不会状态错误?
有经验的开发者知道应使用数据库事务,让多条数据库查询要么全部执行(事务提交/commit),要么全部取消掉(事务回滚/rollback)。
而筋斗云已经帮我们自动使用了事务确保数据一致性。
筋斗云一次接口调用中的所有数据库查询都在一个事务中。 开发者一般不必自行使用事务,除非为了优化并发和数据库锁。
- 筋斗云接口编程 / 常用操作(三)
- 筋斗云接口编程 / 常用操作(一)
- 筋斗云接口编程 / 常用操作(二)
- 筋斗云接口编程 / 对象型接口(三)
- 筋斗云接口编程
- 筋斗云接口编程 / 对象型接口(二)
- 筋斗云接口编程 / 对象型接口(四)
- 筋斗云接口编程 / 函数型接口
- 筋斗云接口编程 / 函数型接口
- 筋斗云接口编程 / 函数型接口
- 筋斗云接口编程 / 函数型接口
- 筋斗云接口编程 / 函数型接口
- 筋斗云接口编程 / 函数型接口
- 筋斗云接口编程 / 对象型接口
- 筋斗云接口编程 / 接口返回前回调
- 筋斗云接口编程 / 非标准对象接口
- 筋斗云接口编程 / 虚拟字段(二)
- 筋斗云接口编程 / 分页机制
- 筋斗云接口编程 / 常用操作(一)
- java swing selected 列表
- 筋斗云接口编程 / 常用操作(二)
- jsp页面格式化数字或时间
- 关于memcache的知识
- 筋斗云接口编程 / 常用操作(三)
- 更改ubuntu的pyhton版本
- Ajax(一)
- PortFolioFrontier
- 考研复试系列——第五节 并查集
- 长整形的使用及cin加速
- 斐波那契查找(黄金分割法查找)
- C++中构造函数的作用
- javaee的增删改查