实例演示常用 的CURD操作,特别是各种常用组合,如fetch+while…
一、预处理参数绑定
PDO预处理
预处理的本质是sql语句的动态绑定
动态绑定就是执行时才绑定真实数据SELECT * FROM `表名` WHERE `id` > ?
静态绑定,数据直接写到SQL语句中SELECT * FROM `表名` WHERE `id` > 1
1. 动态绑定方式
1.1 匿名参数+索引数组
namespace pdo_edu;
use PDO;
$db = new PDO('mysql:dbname=phpedu', 'phpedu', 'phpedu');
//匿名参数:?
$sql = 'INSERT `staff` SET `name` = ?, `gender` = ?, `email` = ?;';
$stmt = $db->prepare($sql);
//SQL语句中占位符“?”,用索引数组绑定真实数据
$data = ['admin', 0, 'admin@php.cn'];
$stmt->execute($data);
echo '<hr>';
//打印SQL预处理命令
$stmt->debugDumpParams();
echo '<br>'.$stmt->errorCode().'<br>';
print_r($stmt->errorInfo());
echo '<br>id = '.$db->lastInsertId().'<br>';
1.2 命名参数+关联数组
namespace pdo_edu;
use PDO;
$db = new PDO('mysql:dbname=phpedu', 'phpedu', 'phpedu');
//命名参数:“:xxxx”不用和前面一一对应
$sql = 'INSERT `staff` SET `name` = :xname, `gender` = :pgender, `email` = :demail;';
$stmt = $db->prepare($sql);
//SQL语句中占位符“:xxxx”,用关联数组绑定真实数据
// $data = [':xname' => 'admin', ':pgender' => 0, ':demail' => 'admin@php.cn'];
//去掉冒号也是可以的
$data = ['xname' => 'admin1', 'pgender' => 1, 'demail' => 'admin1@php.cn'];
$stmt->execute($data);
echo '<hr>';
//打印SQL预处理命令
$stmt->debugDumpParams();
echo '<br>'.$stmt->errorCode().'<br>';
print_r($stmt->errorInfo());
echo '<br>id = '.$db->lastInsertId().'<br>';
“匿名参数+索引数组”和“命名参数+关联数组”用哪个好?
用哪个都可以,看个人喜好。
1.3 参数绑定:值绑定 bindValue()
/**
* 为什么要单独设置参数,而不是在execute()时传参?
* execute()默认参数都是字符类型
* 通常数字型字符写入数据表时,会转换成正确类型,不会有问题。
* 但在分页操作时,会导致错误。
* 在参数绑定时,强制类型限制,就很有必要。
*/
namespace pdo_edu;
use PDO;
$db = new PDO('mysql:dbname=phpedu', 'phpedu', 'phpedu');
//匿名参数:?
$sql = 'INSERT `staff` SET `name` = ?, `gender` = ?, `email` = ?;';
$stmt = $db->prepare($sql);
//bindValue()值绑定,静态绑定,所有参数有确定值。
// bindValue(key, value, type),匿名占位符,索引从1开始。
// $stmt->bindValue(1, 'admin3', PDO::PARAM_STR);
// $stmt->bindValue(2, 0, PDO::PARAM_INT);
// $stmt->bindValue(3, 'admin3@php.cn', PDO::PARAM_STR);
// 上面是写死的,更灵活应该用数组传参。
list($name, $gender, $email) = ['admin4', 1, 'admin4@php.cn'];
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $gender, PDO::PARAM_INT);
$stmt->bindValue(3, $email, PDO::PARAM_STR);
list($name, $gender, $email) = ['admin5', 0, 'admin5@php.cn'];
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $gender, PDO::PARAM_INT);
$stmt->bindValue(3, $email, PDO::PARAM_STR);
$stmt->execute();
echo '<hr>';
//打印SQL预处理命令
$stmt->debugDumpParams();
echo '<br>'.$stmt->errorCode().'<br>';
print_r($stmt->errorInfo());
echo '<br>id = '.$db->lastInsertId().'<br>';
每插入一条就得绑定一次,也不方便灵活。
1.4 参数绑定:引用绑定bindParam()
namespace pdo_edu;
use PDO;
$db = new PDO('mysql:dbname=phpedu', 'phpedu', 'phpedu');
//heredoc
$sql = <<<SQL
INSERT `staff`
SET `name` = ?, `gender` = ?, `email` = ?;
SQL;
$stmt = $db->prepare($sql);
// 引用绑定
$stmt->bindParam(1, $name, PDO::PARAM_STR);
$stmt->bindParam(2, $gender, PDO::PARAM_INT);
$stmt->bindParam(3, $email, PDO::PARAM_STR);
// list($name, $gender, $email) = ['admin6', 1, 'admin6@php.cn'];
// $stmt->execute();
// echo '<hr>';
// 在增加两条条
// list($name, $gender, $email) = ['admin7', 0, 'admin7@php.cn'];
// $stmt->execute();
// echo '<hr>';
// list($name, $gender, $email) = ['admin8', 1, 'admin8@php.cn'];
// $stmt->execute();
// echo '<hr>';
// $stmt->execute();
// echo '<hr>';
// //打印SQL预处理命令
// $stmt->debugDumpParams();
// echo '<br>'.$stmt->errorCode().'<br>';
// print_r($stmt->errorInfo());
// echo '<br>id = '.$db->lastInsertId().'<br>';
// 用循环和二维数组添加多条
$data = [
['admin9', 0, 'admin9@php.cn'],
['admin10', 1, 'admin10@php.cn'],
['admin11', 0, 'admin11@php.cn'],
];
foreach($data as list($name, $gender, $email)){
$stmt->execute();
echo '<hr>';
//打印SQL预处理命令
$stmt->debugDumpParams();
echo '<br>'.$stmt->errorCode().'<br>';
print_r($stmt->errorInfo());
echo '<br>id = '.$db->lastInsertId().'<br>';
}
1.5 错误处理
namespace pdo_edu;
use PDO;
$db = new PDO('mysql:dbname=phpedu', 'phpedu', 'phpedu');
//heredoc
$sql = <<<SQL
INSERT `staff` SET `name` = ?, `gender` = ?, `email` = ?;
SQL;
$stmt = $db->prepare($sql);
//注释“引用绑定”,引起错误
// $stmt->bindParam(1, $name, PDO::PARAM_STR);
// $stmt->bindParam(2, $gender, PDO::PARAM_INT);
// $stmt->bindParam(3, $email, PDO::PARAM_STR);
$data = [
['admin12', 0, 'admin12@php.cn'],
//['admin13', 0, 'admin13@php.cn'],
];
foreach($data as list($name, $gender, $email)){
if($stmt->execute()){
if($stmt->rowCount() > 0){
echo 'sql执行成功,id ='.$db->lastInsertId().'<br>';
echo '<hr>';
}else{
echo '执行失败';
print_r($stmt->errorInfo());
}
}else{
echo 'sql执行失败';
print_r($stmt->errorInfo());
}
}
Tips
- else:应用于开发调试阶段,生产环境中应将错误信息集中写到日志文件中。
- sql执行失败很常见,通常是语法错误,例如字段名写错等。
- 新增失败通常是权限问题,如没有插入权限或者当前表被锁定只读等,磁盘满也有可能。
1.6 更新
namespace pdo_edu;
use PDO;
$db = new PDO('mysql:dbname=phpedu', 'phpedu', 'phpedu');
//heredoc
$sql = <<<SQL
UPDATE `staff` SET `name` = ?, `gender` = ?, `email` = ?
WHERE `id`= ?;
SQL;
// !!!!最高提示:禁止无条件更新,生产环境必须杜绝。
// stripos()忽略大小写
if (false === stripos($sql, 'where'))
{
exit('禁止无条件更新!');
}
$stmt = $db->prepare($sql);
$stmt->bindParam(1, $name, PDO::PARAM_STR);
$stmt->bindParam(2, $gender, PDO::PARAM_INT);
$stmt->bindParam(3, $email, PDO::PARAM_STR);
$stmt->bindParam(4, $id, PDO::PARAM_INT);
$data = [
['admin8', 0, 'admin8@php.cn', 8],
];
foreach($data as list($name, $gender, $email, $id)){
if($stmt->execute()){
if($stmt->rowCount() > 0){
echo '成功更新了'.$stmt->rowCount().'条记录<br>';
echo '<hr>';
}else{
echo '更新重复:没有记录被更新!<br>';
print_r($stmt->errorInfo());
$stmt->debugDumpParams();
}
}else{
echo 'sql执行失败';
print_r($stmt->errorInfo());
}
}
成功时,
重复的更新将被拦截,
....
//不写条件WHERE测试
$sql = <<<SQL
UPDATE `staff` SET `name` = ?, `gender` = ?, `email` = ?
;
SQL;
// 最高提示:禁止无条件更新,生产环境必须杜绝。
// stripos()忽略大小写
if (false === stripos($sql, 'where'))
{
exit('禁止无条件更新!');
}
....
1.7 删除
namespace pdo_edu;
use PDO;
$db = new PDO('mysql:dbname=phpedu', 'phpedu', 'phpedu');
//heredoc
$sql = <<<SQL
DELETE FROM `staff`
WHERE `id`= ?;
SQL;
// 最高提示:禁止无条件删除,生产环境必须杜绝。
// stripos()忽略大小写
if (false === stripos($sql, 'where'))
{
exit('禁止无条件删除!');
}
$stmt = $db->prepare($sql);
$stmt->bindParam(1, $id, PDO::PARAM_INT);
$data = [
[11],
[10],
];
foreach($data as list($id)){
echo $id.'<br>';
if($stmt->execute()){
if($stmt->rowCount() > 0){
echo '成功删除了'.$stmt->rowCount().'条记录<br>';
echo '<hr>';
}else{
echo '重复删除:没有记录被删除!<br>';
print_r($stmt->errorInfo());
// $stmt->debugDumpParams();
}
}else{
echo 'sql执行失败';
print_r($stmt->errorInfo());
}
}
1.8 查询
1.8.1 fetch + while
// 查询 fetch + while
namespace pdo_edu;
use PDO;
$db = new PDO('mysql:dbname=phpedu', 'phpedu', 'phpedu');
//heredoc
$sql = <<<SQL
SELECT `id`, `name`, `email` FROM `staff`
LIMIT ?;
SQL;
$stmt = $db->prepare($sql);
// $num = 5;
// $stmt->bindParam(1, $num, PDO::PARAM_INT);
$stmt->bindValue(1, 5, PDO::PARAM_INT);
if($stmt->execute()){
// fetch()逐条获取,指针自动后移指向下一条,失败返回false,成功返回记录。
// $staff = $stmt->fetch(PDO::FETCH_ASSOC);
// if($staff)
// {
// printf('<pre>%s</pre><br>',print_r($staff, true));
// }else
// {
// echo '没有查询到数据!<br>';
// }
while($staff = $stmt->fetch(PDO::FETCH_ASSOC))
{
printf('<pre>%s</pre><br>',print_r($staff, true));
}
}else{
echo 'sql执行失败';
print_r($stmt->errorInfo());
$stmt->debugDumpParams();
}
1.8.2 fetchall
// 查询 fetchall
namespace pdo_edu;
use PDO;
$db = new PDO('mysql:dbname=phpedu', 'phpedu', 'phpedu');
//heredoc
$sql = <<<SQL
SELECT `id`, `name`, `email` FROM `staff`
LIMIT ?;
SQL;
$stmt = $db->prepare($sql);
// $num = 5;
// $stmt->bindParam(1, $num, PDO::PARAM_INT);
$stmt->bindValue(1, 4, PDO::PARAM_INT);
if($stmt->execute()){
// fetchall()获取全部记录。
while($staffs = $stmt->fetchAll(PDO::FETCH_ASSOC))
{
foreach($staffs as
$staff){
printf('<pre>%s</pre><br>',print_r($staff, true));
}
}
}else{
echo 'sql执行失败';
print_r($stmt->errorInfo());
$stmt->debugDumpParams();
}