今天这篇文章,咱们来简单的学习一下 PDO 中的预处理语句以及事务的使用,它们都是在 PDO 对象下的操做,并且并不复杂,简单的应用都能很容易地实现。只不过大部分状况下,你们都在使用框架,手写的机会很是少。php
预处理语句就是准备好一个要执行的语句,而后返回一个 PDOStatement 对象。通常咱们会使用 PDOStatement 对象的 execute() 方法来执行这条语句。为何叫预处理呢?由于它可让咱们屡次调用这条语句,而且能够经过占位符来替换语句中的字段条件。相比直接使用 PDO 对象的 query() 或者 exec() 来讲,预处理的效率更高,它可让客户端/服务器缓存查询和元信息。固然,更加剧要的一点是,占位符的应用能够有效的防止基本的 SQL 注入攻击,咱们不须要手动地给 SQL 语句添加引号,直接让预处理来解决这个问题,相信这一点是你们都学习过的知识,也是咱们在面试时最多见到的问题之一。git
// 使用 :name 形式建立一个只进游标的 PDOStatement 对象 $stmt = $pdo->prepare("select * from zyblog_test_user where username = :username", [PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY]); var_dump($stmt); // object(PDOStatement)#2 (1) { // ["queryString"]=> // string(57) "select * from zyblog_test_user where username = :username" // } $stmt->execute([':username' => 'aaa']); $aUser = $stmt->fetchAll(); $stmt->execute([':username' => 'bbb']); $bUser = $stmt->fetchAll(); var_dump($aUser); // array(1) { // [0]=> // array(8) { // ["id"]=> // string(1) "1" // [0]=> // string(1) "1" // ["username"]=> // string(3) "aaa" // …… var_dump($bUser); // array(1) { // [0]=> // array(8) { // ["id"]=> // string(1) "2" // [0]=> // string(1) "2" // ["username"]=> // string(3) "bbb" // ……
prepare() 方法的第一个参数就是咱们须要执行的 SQL 语句,在这段代码中,咱们使用的是 :xxx 形式的占位符,因此在调用 prepare() 方法返回的 PDOStatement 对象的 execute() 方法时,咱们须要指定占位符的值。在代码中,咱们使用这一条 SQL 语句,经过替换不一样的占位符内容,实现了两次查询。github
prepare() 方法的第二个参数是为返回的 PDOStatement 对象设置的属性。常见用法是:设置 PDO::ATTR_CURSOR 为 PDO::CURSOR_SCROLL,将获得可滚动的光标。 某些驱动有驱动级的选项,在 prepare 时就设置。PDO::ATTR_CURSOR 是设置数据库游标的类型,而 PDO::CURSOR_FWDONLY 的意思是建立一个只进游标的 PDOStatement 对象。此为默认的游标选项,由于此游标最快且是 PHP 中最经常使用的数据访问模式。关于数据库游标的知识你们能够自行查阅相关的内容。面试
此外,PDOStatement 还能够经过 bindParam() 方法来绑定占位符数据,咱们将在后面学习 PDOStatement 对象相关的文章中继续学习。数据库
接下来,咱们再看一下使用 ? 号占位符来实现查询,? 号占位符在绑定的时候是如下标形式进行绑定的。缓存
// 使用 ? 形式建立一个只进游标的 PDOStatement 对象 $stmt = $pdo->prepare("select * from zyblog_test_user where username = ?", [PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY]); $stmt->execute(['aaa']); $aUser = $stmt->fetchAll(); var_dump($aUser); // array(1) { // [0]=> // array(8) { // ["id"]=> // string(1) "1" // [0]=> // string(1) "1" // ["username"]=> // string(3) "aaa" // ……
固然,这种预编译语句不只限于查询语句,增、删、改都是能够的,并且也都是支持占位符的。在 PHP中操做数据库的预处理语句 这篇文章中有详细的示例。服务器
关于事务想必你们也都有必定的了解,因此在这里也不介绍具体的概念了,咱们只看看在 PDO 中事务是如何实现的。首先,咱们先看下在没有事务的状况下会发生什么。框架
$pdo->exec("insert into tran_innodb (name, age) values ('Joe', 12)"); // 成功插入 $pdo->exec("insert into tran_innodb2 (name, age) values ('Joe', 12)"); // 报错中止整个PHP脚本执行 // Fatal error: Uncaught PDOException: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'blog_test.tran_innodb2' doesn't exist
假设这两个表须要同时更新,但第二条语句报错了。在没有事务的状况下,咱们第一条数据是会正常插入成功的,这并非咱们须要的结果。在这时,就须要事务能力的帮助,让咱们可以让两个表要么同时成功,要么同时失败。函数
try { // 开始事务 $pdo->beginTransaction(); $pdo->exec("insert into tran_innodb (name, age) values ('Joe', 12)"); $pdo->exec("insert into tran_innodb2 (name, age) values ('Joe', 12)"); // 不存在的表 // 提交事务 $pdo->commit(); } catch (Exception $e) { // 回滚事务 $pdo->rollBack(); // 输出报错信息 echo "Failed: " . $e->getMessage(), PHP_EOL; // Failed: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'blog_test.tran_innodb2' doesn't exist }
首先就是 beginTransaction() 方法,它是用来关闭数据库的自动提交,并启动一个事务,在这个方法以后,只有遇到 commit() 或者 rollBack() 方法后才会关闭这个事务。学习
commit() 方法就是操做过程当中没有出现意外的话,就将在 beginTransaction() 以后的全部数据操做一块儿打包提交。
rollBack() 是回滚数据,当 beginTransaction() 以后的某一条语句或者代码出现问题时,回滚以前的数据操做,保证 beginTransaction() 以后的全部语句要么都成功,要么都失败。
就是这样三个简单的函数,就为咱们完成了整个事务操做。关于事务的深刻学习咱们会在未来深刻地研究 MySQL 时再进行探讨。在这里咱们须要注意的是,PDO 对象最好指定错误模式为抛出异常,若是不指定错误模式的话,事务中出现的错误也不会直接报错,而是返回错误码,咱们须要经过错误码来肯定是否提交或回滚。这样远没有异常机制来的简洁直观。
咱们简单的梳理并学习了一下 PDO 中的预处理和事务相关的知识,接下来就要进入 PDOStatement 对象相关内容的学习。PDOStatement 对象就是 PDO 的预处理对象,也就是在平常开发中咱们会接触到的最多的数据操做对象。这块但是重点内容,你们可不能松懈了哦!
测试代码:
参考文档:
https://www.php.net/manual/zh/pdo.prepare.php
https://www.php.net/manual/zh/pdo.begintransaction.php
https://www.php.net/manual/zh/pdo.commit.php
各自媒体平台都可搜索【硬核项目经理】