简介
PDO(PHP Data Objects)是一种在 PHP 里连接数据库的使用接口。PDO 与 mysqli 曾经被建议用来取代原本 PHP 在用的 mysql 相关函数,基于数据库使用的安全性,因为后者欠缺对于 SQL 注入的防护。mysqli 是只用于 mysql,而 PDO 可以适用于多种数据库,有足够的适应性.所以我们只学习 PDO 数据库连接.
PHP 数据对象(PDO) 扩展为 PHP 访问数据库定义了一个轻量级的一致接口。实现 PDO 接口的每个数据库驱动可以公开具体数据库的特性作为标准扩展功能。 注意利用 PDO 扩展自身并不能实现任何数据库功能;必须使用一个具体数据库的 PDO 驱动来访问数据库服务。
PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。 PDO 不提供数据库抽象层;它不会重写 SQL,也不会模拟缺失的特性。如果需要的话,应该使用一个成熟的抽象层。
从 PHP 5.1 开始附带了 PDO,在 PHP 5.0 中是作为一个 PECL 扩展使用。 PDO 需要 PHP 5 核心的新 OO 特性,因此不能在较早版本的 PHP 上运行。
由于普通的 sql 语句会有 MySQL 注入的风险,所以我们通常都使用预处理语句执行 sql 语句,并且具有更高的执行效率.以下只演示预处理语句.
同时我们需要了解 PDO,PDOStatement,还有 PDOException。其中 PDOException 是 PDO 错误/异常类。
PDO 对预处理语句的支持需要使用 PDOStatement 类对象,但该类对象并不是通过 NEW 关键字实例化出来的,而是通过 PDO 对象中的 prepare()方法,在数据库服务器中准备好一个预处理的 SQL 语句后直接返回的。如果通过之前执行 PDO 对象中的 query()方法返回的 PDOStatement 类对象,只代表的是一个结果集对象。而如果通过执行 PDO 对象中的 prepare()方法产生的 PDOStatement 类对象,则为一个查询对象,能定义和执行参数化的 SQL 命令。
PDO 预处理可以批量进行重复性操作,可实现模块化处理(可以自动转义)
以上内容详细参考博客园博文或者它引用的 CSDN 博文,里面对于 PDO 和 PDOStatement 也有比较完整的介绍,我认为一定要看完全文,没看完就没有掌握 PDO,我这里不重复了,这不等于说这些内容不是必要的,恰恰相反,这些内容是 PDO 操作的核心知识点,只是已经阐述得很完整,我就不好再重复了:
PDO、PDOStatement、PDOException。
PDO 中包含三个预定义的类,它们分别是 PDO、PDOStatement、PDOException。
PDO 中包含三个预定义的类—PDO、PDOStatement 和 PDOException
演示 PDO 预处理 CRUD
mysql 支持两种参数占位方式:问号参数“?”和命名参数“:字段名”;命名参数更明确。
以下简单演示利用 PDO 预处理语句进行 CRUD 的过程。
下图是初始数据库的 user 数据表.
// 第一步:连接数据库
$dbms='mysql'; //数据库类型
$host='localhost'; //数据库主机名
$dbName='phplesson'; //数据库名
$$username='root'; //数据库连接用户名
$password='root'; //数据库连接密码
//dsn数据源
$dsn="$dbms:host=$host;dbname=$dbName";
//数据库操作需要trycatch包裹捕获异常,下面演示PDO对象创建,之后演示PDO对象操作,不包括增删改,这些都让PDOStatement对象实现
// PDOStatement对象由pdo->query()或者是pdo->prepare()返回
try{
// 第二步:创建pdo连接,返回值是一个PDO对象,对象名自定义。如果需要数据库长连接可以在括号里的最后增加一个参数:array(PDO::ATTR_PERSISTENT=>true)
$conn=new PDO($dsn,$username,$password);
// 设置了 ERRMODE 为 WARNING,可以在遇到一个 E_WARNING 级别的错误的时候抛出
// $conn=new PDO($dsn,$username,$password,[PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING]);
// 全局设置PDO获取返回数据格式为关联数组
$conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC);
echo "连接成功!<br>";
// 以下演示PDO对象部分方法。
// PDO对象的增删改操作基本上不再演示,统一用PDOStatement方法代替
echo '<br>---------------遍历输出数据表内容---------------------<br>';
// 遍历数据表user的值,pdo->query返回PDOStatement对象
// 注意:sql语句不区分大小写
// 打印结果是数据表中的值,每一行数据表记录是一个数组
foreach($conn->query('SELECT * FROM user') as $row){
print_r($row);
echo '<br>';
}
// 返回查找到的记录总条数,此处为2
echo $conn->query('SELECT * FROM user')->rowCount();
echo '<br>';
// 返回最后插入行的id或者是序列号,此处为0.
echo $conn->lastInsertID();
echo '<br>';
// 返回上一次句柄上一次操作的错误信息数组
print_r($conn->errorInfo());
echo '<br>';
// 返回跟数据库句柄上一次操作相关的SQLSTATE码
echo $conn->errorCode();
echo '<br>';
$pdo=null; //关闭PDO
echo '<br>---------------------------------------------------------<br>';
}catch(\Exception $e){
die("PDO连接错误!".$e->getMessage()."<br>");
}
echo '<br>---------------PDOStatement操作数据库---------------------<br>';
// 下面演示PDOStatment对象查找操作,使用问号占位符
$sql='SELECT * FROM user WHERE username=? AND age>?';
$name='ccc';
$age='1';
// 第三步,通过PDO->prepare(sql语句)创建PDOStatement对象,然后利用这个对象进行增删查改操作并返回操作结果
// PDO对象->prepare返回一个PDOStatement对象
$stmt=$conn->prepare($sql);
// $stmt->bindParam(),$stmt->bindValue(),绑定一个参数到指定的变量名。以下演示bindParam()和bindValue()的差别
echo '<br>---------------bindParam---------------------<br>';
// PDO::PARAM_STR,限制为字符串,12位
// PDO::PARAM_INT,限制为整型,8位
$stmt->bindParam(1,$name,PDO::PARAM_STR, 12);
$stmt->bindParam(2,$age,PDO::PARAM_INT, 8);
//$stmt->execute()执行数据库操作
$stmt->execute();
// rowCount()返回查询到的记录条数,此处为1
echo $stmt->rowCount();
echo '<br>';
// 改变查询参数,把$age的字符串改成数字,此处返回查询结果1
$name='ddd';
$age=1;
$stmt->execute();
echo $stmt->rowCount();
echo '<br>';
// 再次改变查询参数,把$age要求改成11,此处返回查询结果为0
$name='ddd';
$age=11;
$stmt->execute();
echo $stmt->rowCount();
echo '<br>';
// 以下演示bindValue()
echo '<br>---------------bindValue---------------------<br>';
$name='ccc';
$age=11;
$stmt->bindValue(1,$name);
$stmt->bindValue(2,$age);
$stmt->execute();
echo $stmt->rowCount();
echo '<br>';
// 以上返回结果是1
// 下面修改参数值,但是返回依然是1.因为bindValue()一次绑定后不再理会后面的参数值改变
$name='ddd';
$age=11;
echo $stmt->rowCount();
echo '<br>';
echo '<br>---------------命名占位符---------------------<br>';
$sql='SELECT * FROM user WHERE username= :name AND password= :password';
// echo $sql;
echo '<br>';
$stmt=$conn->prepare($sql);
$name='ccc';
$password='123456';
// bindParam:限制为字符串类型
$stmt->bindParam(':name',$name);
$stmt->bindParam(':password',$password);
// 执行
$stmt->execute();
// var_dump($stmt);
echo $stmt->rowCount();
echo '<br>';
// $stmt->errorInfo和$stmt->errorCode可以返回上一次操作的错误信息数组和代码,和PDO对象方法一致
print_r($stmt->errorInfo());
echo '<br>';
print_r($stmt->errorCode());
echo '<br>';
echo '<br>---------------PDOStatement插入---------------------<br>';
// 下面演示插入操作
$sql='INSERT INTO user (username,password) VALUES (?,?)';
// echo $sql;
$stmt=$conn->prepare($sql);
$name='fff';
$password=md5('123456');
$age=56;
$stmt->bindParam(1,$name);
$stmt->bindParam(2,$password);
// $stmt->bindParam(3,$age);
$stmt->execute();
echo $stmt->rowCount();
echo '<br>';
// 可以使用数组形式直接传入PDO对象,不需要bindValue/bindParam
echo '<br>---------------PDOStatement使用数组形式直接插入---------------------<br>';
$stmt->execute(array('lll',md5('234567')));
if($stmt->rowCount()==1){
echo '插入成功';
echo '<br>';
// PDO对象的lastInsertId(columnname)返回最后一个插入的id值,如果指定name则是返回columnname字段,此处返回9
echo '插入id是:'.$conn->lastInsertId();
echo '<br>';
}else{
print_r($stmt->errorInfo());
}
// 下面演示更新操作:
echo '<br>---------------PDOStatement更新---------------------<br>';
$sql='UPDATE user SET age=? WHERE username=?';
// echo $sql;
$stmt=$conn->prepare($sql);
$age=10;
$name='fff';
$stmt->execute(array($age,$name));
if($stmt->rowCount()!=0){
echo '更新成功!<br>';
}else{
print_r($stmt->errorInfo());
}
// 下面演示删除操作:
echo '<br>---------------PDOStatement删除---------------------<br>';
$sql='DELETE FROM USER WHERE username = ?';
$stmt=$conn->prepare($sql);
$name='iii';
$stmt->bindParam(1,$name,PDO::PARAM_STR);
$stmt->execute();
if($stmt->rowCount()!=0){
echo '删除成功!<br>';
}else{
print_r($stmt->errorInfo());
}
echo '<br>---------------PDOStatement模糊查询删除---------------------<br>';
// 模糊删除,需要在$sql语句中用like,在参数中用%代替模糊部分。左边就加左边%,右边就加右边。
// 模糊查询的参数中不能够用单引号包裹%,必须用双引号转义
$sql='DELETE FROM USER WHERE username LIKE ?';
$stmt=$conn->prepare($sql);
$name='l';
$res=$stmt->execute(array("%$name%"));
if($stmt->rowCount()!=0){
echo '删除成功!<br>';
}else{
var_dump($stmt->errorInfo());
}
echo '<br>---------------PDOStatement->fetch()获取一行---------------------<br>';
// 从一个 PDOStatement 对象相关的结果集中获取下一行。fetch_style 参数决定 POD 如何返回行。
// mixed PDOStatement::fetch ([ int $fetch_style [, int $cursor_orientation = PDO::FETCH_ORI_NEXT [, int $cursor_offset = 0 ]]] )
$sql='SELECT id,username,age FROM user WHERE AGE>?';
$stmt=$conn->prepare($sql);
$stmt->execute([0]);
while($user=$stmt->fetch(PDO::FETCH_ASSOC)){
vprintf('<li>%s:%s | %s </li>',$user);
}
echo '<br>---------------PDOStatement->fetchAll()获取多行---------------------<br>';
// fetchAll()方法与上一个方法fetch()类似,但是该方法只需要调用一次就可以获取结果集中的所有行,并赋给返回的数组(二维)。
$sql='SELECT id,username,age FROM user WHERE id>?';
$stmt=$conn->prepare($sql);
$stmt->execute([1]);
$res=$stmt->fetchAll();
$output=<<<table
<table border=1 cellspacing=0 width=50% style="text-align:center" >
<thead>
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
</tr>
</thead>
<tbody>
table;
echo $output;
foreach($res as $user){
echo '<tr><td>',$user['id'],'</td><td>',$user['username'],'</td><td>',$user['age'],'</td></tr>';
}
echo "</tbody></table>";
// 第四步:关闭PDO,切记
$conn=null;
最后输出表格如下(数据不完全一致,因为还有其他增删改查操作):