今天这篇文章,我们来简单了解一下PDO中preparedstatements和transactions的使用。它们都是在PDO对象下运行的,并不复杂,简单的应用也能轻松实现。只是大多数情况下大家都在用框架,手写的机会很少。Preparedstatement函数Preparedstatement就是准备一个要执行的语句,然后返回一个PDOStatement对象。一般我们会使用PDOStatement对象的execute()方法来执行这条语句。为什么叫预处理呢?因为它允许我们多次调用这条语句,并且可以用占位符替换语句中的字段条件。预处理比直接在PDO对象上使用query()或exec()更有效,允许客户端/服务器缓存查询和元信息。当然,更重要的一点是占位符的应用可以有效的防止基本的SQL注入攻击。我们不需要手动给SQL语句加上引号,让预处理直接解决这个问题。相信这是每个??人都应该学习的Previousknowledge,也是我们面试时最常问到的问题之一。//使用:name形式创建一个仅游标的PDOStatement对象$stmt=$pdo->prepare("select*fromzyblog_test_userwhereusername=:username",[PDO::ATTR_CURSOR=>PDO::CURSOR_FWDONLY]);var_dump($stmt);//object(PDOStatement)#2(1){//["queryString"]=>//string(57)"select*fromzyblog_test_userwhereusername=:username"//}$stmt->执行([':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]=>//数组(8){//["id"]=>//字符串(1)"2"//[0]=>//字符串(1)"2"//["username"]=>//string(3)"bbb"//...prepare()方法的第一个参数是我们需要执行的SQL语句。在这段代码中,我们使用了:xxx形式的占位符,所以在调用prepare的时候在执行()方法返回的PDOStatement对象的execute()方法时,我们需要在代码中指定占位符的值。我们使用这条SQL语句通过替换不同的占位符内容来实现两个查询。prepare()方法的第二个参数是为返回的PDOStatement对象设置的属性。一个常见的用法是:将PDO::ATTR_CURSOR设置为PDO::CURSOR_SCROLL以获得可滚动的游标。某些驱动程序具有驱动程序级别的选项,这些选项是在准备期间设置的。PDO::ATTR_CURSOR是设置数据库游标的类型,PDO::CURSOR_FWDONLY是指创建一个只进入游标的PDOStatement对象。这是默认的游标选项,因为它是PHP中最快和最常用的数据访问模式。关于数据库游标的知识,可以自行查看相关内容。此外,PDOStatement还可以通过bindParam()方法绑定占位符数据,我们将在后面的PDOStatement对象相关文章中继续学习。接下来,让我们看看使用?占位符来实现查询。这?占位符在绑定时以下标的形式绑定。//以?的形式创建一个仅限游标的PDOStatement对象$stmt=$pdo->prepare("select*fromzyblog_test_userwhereusername=?",[PDO::ATTR_CURSOR=>PDO::CURSOR_FWDONLY]);$stmt->execute(['aaa']);$aUser=$stmt->fetchAll();var_dump($aUser);//数组(1){//[0]=>//数组(8){//["id"]=>//字符串(1)"1"//[0]=>//string(1)"1"//["username"]=>//string(3)"aaa"//...当然,这种预编译语句不仅限于查询语句,它可以增删改查,都支持占位符。PHP操作数据库的准备语句这篇文章中有详细的例子。交易能力大家对交易肯定有一定的了解,这里就不介绍具体的概念了。我们就来看看PDO中的事务是如何实现的。首先,让我们看看没有事务会发生什么。$pdo->exec("insertintotran_innodb(name,age)values('Joe',12)");//插入成功$pdo->exec("insertintotran_innodb2(name,age)values('Joe',12)");//报错停止整个PHP脚本的执行//Fatalerror:UncaughtPDOException:SQLSTATE[42S02]:Basetableorviewnotfound:1146Table'blog_test.tran_innodb2'doesn'texistassumingthesetwotables它需要同时更新,但是第二条语句报错。在没有事务的情况下,我们的第一条数据会插入成功,这不是我们需要的结果。这时候我们就需要事务能力的帮助,让我们可以让两张表要么同时成功,要么同时失败。try{//开始事务$pdo->beginTransaction();$pdo->exec("insertintotran_innodb(name,age)values('Joe',12)");$pdo->exec("insertintotran_innodb2(name,age)values('Joe',12)");//不存在的表//提交事务$pdo->commit();}catch(Exception$e){//回滚事务$pdo->rollBack();//输出错误信息echo"Failed:".$e->getMessage(),PHP_EOL;//Failed:SQLSTATE[42S02]:Basetableorviewnotfound:1146Table'blog_test.tran_innodb2'doesn'texist}首先是beginTransaction()方法,用于关闭数据库的自动提交并开始交易。在这个方法之后,只有遇到commit()或者rollBack()方法才会关闭事务。commit()方法是将beginTransaction()之后的所有数据操作打包提交,如果操作过程中没有发生意外的话。rollBack()是回滚数据。当beginTransaction()后的某条语句或代码出现问题时,回滚之前的数据操作,保证beginTransaction()后的所有语句要么成功,要么失败。就是这样三个简单的函数,为我们完成了整个交易操作。关于事务的深入研究,我们以后深入学习MySQL的时候再讨论。这里需要注意的是,最好将PDO对象的错误模式指定为抛出异常。如果不指定错误模式,事务中的错误不会直接报错,而是返回一个错误码。我们需要将错误码传递给决定是提交还是回滚。这远不如异常机制简洁直观。综上所述,我们简单的梳理和学习了PDO中的预处理和事务相关的知识,接下来我们将进入PDOStatement对象相关内容的学习。PDOStatement对象是PDO的预处理对象,是我们在日常开发中接触到最多的数据操作对象。这是重点内容,大家不能松懈!测试代码:https://github.com/zhangyue0503/dev-blog/blob/master/php/202008/source/PHP%E4%B8%AD%E7%9A%84PDO%E6%93%8D%E4%BD%9C%E5%AD%A6%E4%B9%A0%EF%BC%88%E4%BA%8C%EF%BC%89%E9%A2%84%E5%A4%84%E7%90%86%E8%AF%AD%E5%8F%A5%E5%8F%8A%E4%BA%8B%E5%8A%A1.php参考文档:https://www.php.net/manual/zh/pdo.prepare.phphttps://www.php.net/manual/zh/pdo.begintransaction.phphttps://www.php.net/manual/zh/pdo.commit.phphttps://www.php.net/manual/zh/pdo.rollback.php各媒体平台均可搜索【硬核项目经理】
