PDO是
PHP Data Object
(PHP数据对象)的简写,它的功能是提供一个数据访问
抽象层,使得不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据,PHP从5.1开始附带PDO
一、连接与连接管理
1、使用PDO的构造函数来连接数据库,以连接mysql为例
$pdo = new PDO('mysql:host=localhost;dbname=test', $user, $pwd);
如果连接错误,那么抛出一个PDOException
异常,可以通过捕获该异常来处理错误状态
2、关闭一个连接
连接数据库成功后,会返回一个PDO类的实例,连接会在PDO对象的生存周期内保持活动。如果要关闭连接,则就需要销毁对象,来确保没有任何引用再指向它。最简单的方法,就是赋予对象一个NULL
值。如果没有这么做的话,那么在PHP脚本结束后,才会自动关闭连接
$pdo = NULL;
3、使用永久连接
使用永久连接,需要在最后一个参数传入配置信息。而且对于永久连接,只能使用构造函数传入配置信息,使用setAttribute()
方法无效
$pdo = new PDO('mysql:host=localhost;dbname=test', $user, $pwd, [
PDO::ATTR_PERSISTENT => true
]);
二、事务与自动提交
使用$pdo->beginTransaction()
来开启事务,使用$pdo->commit()
来提交事务、$pdo->rollBack()
来回滚事务
注意: 使用$pdo->beginTransaction()
开启事务,那么PDO将在必要时自动回滚(如出错、脚本结束或者终止后尚有未完成的事务)。如果手动发出启动事务查询
通知,那么PDO将无法知晓,并且必要时不会发生回滚
三、预处理语句与存储过程
1、预处理的好处:
- 数据库查询语句,自准备好后,运行需要经过分析、编译、优化的过程。对于同样的查询,而个别条件不一致的情况,使用预处理后便可不需要重复的分析/编译/优化周期,从而占用更少的资源,运行地更快。
- 提供给预处理语句的参数不需要用引号包围,驱动程序会自动地处理,从而经过预处理的语句,可以避免发生SQL注入的情况
2、使用预处理语句进行重复插入
$sql = $pdo->prepare('INSERT INTO students (name, gender) VALUES(:name, :gender)');
$sql->bindParam(':name', $name);
$sql->bindParam(':gender', $gender);
// 插入第一条数据
$name = "RuphiLau";
$gender = "男";
$sql->exec();
// 插入第二条数据
$name = "KPP";
$gender = "女";
$sql->exec();
也可以使用?
取代:name
、:gender
作为占位符,相应的代码可以改为:
$sql = $pdo->prepare('INSERT INTO students (name, gender) VALUES(?, ?)');
$sql->bindParam(1, $name);
$sql->bindParam(2, $gender);
// 插入第一条数据
$name = "RuphiLau";
$gender = "男";
$sql->exec();
// 插入第二条数据
$name = "KPP";
$gender = "女";
$sql->exec();
3、预处理语句避免SQL注入
$sql = $pdo->prepare('SELECT * FROM students WHERE sid = ?');
if( $sql->execute([ $_GET['sid'] ]) ) {
// ...
}
4、占位符必须放在整个值的位置,如:
// 下面这种写法,占位符无效
$sql = $pdo->prepare("SELECT * FROM students WHERE name LIKE '%?%'");
$sql->execute( [ $_GET['name'] ] );
// 正确写法
$sql = $pdo->prepare("SELECT * FROM students WHERE name LIKE ?");
$sql->execute( ['%'.$_GET['name'].'%'] );
占位符中也不能包括“-”
5、带输出参数调用存储过程
$sql = $pdo->prepare('CALL sp_returns_string(?)');
$sql->bindParam(1, $rtn, PDO::PARAM_STR, 4000);
$sql->exec();
echo $rtn;
6、带输入、输出参数调用存储过程
$sql = $pdo->prepare('CALL sp_takes_string_returns_string(?)');
$val = 'Hello';
$sql->bindParam(1, $val, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
$sql->exec();
echo $val;
四、错误与错误处理
PDO提供三种不同的错误处理模式:
PDO::ERRMODE_SILENT
默认模式,PDO只简单地设置错误码。可以使用$pdo->errorCode()
和$pdo->errorInfo()
方法来检查语句和数据库对象。如果是错误是由于对语句对象的调用产生的,那么可以使用$sql->errorCode()
和$sql->errorInfo()
PDO::ERRMODE_WARNING
除了设置错误码之外,PDO还将发出一条传统的E_WARNING
信息PDO::ERRMODE_EXCEPTION
除了设置错误码之外,还将抛出一个PDOException
异常类并设置它的属性,来反射错误码和错误信息
设置错误模式的方法:$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)
五、大对象(LOBs)
可以在数据库中存储“大”数据,“大”意味着4kb及以上。通常大对象的本质是文本或者二进制。所以可以在$pdo->bindParam()
或者$pdo->bindColumn()
调用中第三个参数传入PDO::PARAM_LOB
来使用大数据类型。PDO::PARAM_LOB
告诉PDO采用流来映射数据,这样子就可以使用PHP Streams API
来操作数据
1、插入一张图片到数据库
$sql = $pdo->prepare('INSERT INTO avatars (data) VALUES(?)');
$fp = fopen("someAvatar.jpg", 'rb');
$sql->bindParam(1, $fp, PDO::PARAM_LOB);
$pdo->beginTransaction();
$sql->exec();
$pdo->commit();
2、从数据库中获得一张图片
$sql = $pdo->prepare('SELECT data FROM avatars WHERE id=?');
$sql->exec($_GET['id']);
$sql->bindColumn(1, $data, PDO::PARAM_LOB);
$sql->fetch(PDO::FETCH_BOUND);
header("Content-type: image/jpeg");
fpassthru($data);