跳转到主内容
极星编程网:以代码为星,赴技术山海!

PHP开发笔记系列(一)-PDO使用

之前一段时间,开始了php的研究,看了关于pdo的一些资料,发现不错,整理和总结一下,作为开发笔记,留待日后使用,《php开发笔记系列(一)-pdo使用》。

pdo是php data objects的简称,是一种数据库访问抽象层。pdo是用于多种数据库的一致接口。类比的说,pdo做的事情类似于java中的持久层框架(hibernate、openjpa)的功能,为异构数据库提供一个统一的编程接口,这样就不必再使用mysql_*、pg_*这样的函数,也不必再写自己的"genericdao"了。pdo在php5.1的时候一起发布,所以我们用的php5.2、php5.3都已经可以使用。

为了方便,我们使用mysql5来做演示。

0. 建立实验环境数据库及相关表

PHP 8.5.5 PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。

下载Sql代码CREATETABLE `blog` (`id`int(10)NOTNULL AUTO_INCREMENT,`title`varchar(255)NOTNULL,PRIMARYKEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=latin1

1. 使用PDO访问数据库

通过PDO访问数据库的步骤是:a)指定dsn、username、password,b)通过#a中的设置构造PDO对象,代码如下:Php代码file:pdo-access.php url:http://localhost:88/pdo/pdo-access.php php getMessage();}?>备注:DSN即Data Source Name-数据源名称,提供数据库的连接信息,包括三部分,PDO驱动名称(MySQL、SQLite、PostgreSQL等)、冒号和驱动特定的语法。但是一般情况下,我们都很难记住这些,可以下载个php manual查,也可以到php的官网查。

2. 使用Query方法查询数据

在#1的基础上,连接数据库成功后,构造SQL语句,调用query方法返回结构数组,通过foreach进行数据结果遍历,代码如下:Php代码file:pdo-query.php url:http://localhost:88/pdo/pdo-query.php?title=title1 php query($sql)as$row){print$row['id']."\t";print$row['title']."\t";}} catch (PDOException$e) {echo'Errors occur when query data!\n';echo$e->getMessage();}?>备注:一般情况下, 通过构造SQL语句的方法来进行query、update、insert、delete,都会需要指定where条件,因此不可避免的需要防止SQL注入的问题出现。

例如,正常情况下,当用户输入“title1”时,我们构造的sql语句会是SELECT * FROM blog WHERE title='title1',但是对SQL比较熟悉的用户会输入'OR id LIKE '%,此时我们构造的SQL就会变成SELECT * FROM blog where title='' OR id LIKE '%',这样整张blog 表中的数据都会被读取,因此需要避免,所以需要用到quote方法,把所有用户提供的数据进行转移,从而防止SQL注入的发生。使用quote方法后的sql为$sql = "SELECT * FROM blog WHERE title = ".$dbh->quote($title),转移出来后的sql是SELECT * FROM blog WHERE title = '\'OR id LIKE \'%',把所有的单引号(')都转移了。

3. 使用prepare和execute方法查询数据

如果我们用到的SQL查询是使用频率不高的查询,那么使用query或prepare和execute方法来查询都无太大差别,查询速度也不会差太远。两者不同的是,使用query时,php向数据库发送的sql,每执行一次都需要编译一次,而使用prepare和execute方法,则不需要,因此做大并发量的操作时,使用prepare和execute方法的优势会更加明显。

使用prepare和execute方法的步骤不多,a)构造SQL,b)将SQL传入PDO->prepart方法,得到一个PDOStatement对象,3)调用PDOStatement对象的execute方法,4)通过PDOStatement->fetch或PDOStatement->fetchObject遍历结果集。代码如下:Php代码file:pdo-prepare-fetch.php url:http://localhost:88/pdo/pdo-prepare-fetch.php?title=title1 php prepare($sql);// 为绑定变量赋值$stmt->bindParam(":title",$title, PDO::PARAM_STR);// 执行SQL$stmt->execute();// 以联合数组方式获取结果,并遍历结果while ($row =$stmt->fetch(PDO::FETCH_ASSOC)) {print$row['id']."\t";print$row['title']."\t";}} catch (PDOException$e) {echo'Errors occur when query data!\n';echo$e->getMessage();}?>除了使用上面的PDO::FETCH_ASSOC返回联合数组外,还可以使用fetchObject方法,返回结果集对象,代码如下:Php代码file:pdo-prepare-fetch-object.php url:http://localhost:88/pdo/pdo-prepare-fetch-object.php?title=title1 php prepare($sql);$stmt->bindParam(":title",$title, PDO::PARAM_STR);$stmt->execute();// 以对象数组方式获取结果,并遍历结果while ($row =$stmt->fetchObject()) {print$row->id."\t";print$row->title."\t";}} catch (Exception$e) {echo'Errors occur when query data!\n';echo$e->getMessage();}?>

4. 设置PDO的错误级别

PDO的错误级别分成PDO::ERRMODE_SILENT(默认)、PDO::ERRORMODE_WARNING、PDO::ERRORMODE_EXCEPTION三种。

PDO::ERRMODE_SILENT级别,当出现错误时,会自动设置PDOStatement对象的errorCode属性,但不进行任何其他操作,因此需要我们手工检查是否出现错误(使用empty($stmt->errorCode())),否则程序将继续走下去。

PDO::ERRORMODE_WARNING级别,基本与PDO::ERRMODE_SILENT一致,都是需要使用empty($stmt->errorCode())手工检查。

只需要在创建PDO对象后,加入以下代码即可:$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);或$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);PDO::ERRORMODE_WARNING级别,当出现错误时,系统将抛出一个PDOException,并设置errorCode属性,程序可以通过try{...}catch{...}进行捕捉,否则未catch的exception会导致程序中断,加入以下代码即可:$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);Php代码php

try {...

} catch (Exception$e) {echo'Errors occur when operation!'."";// 获取Exception信息echo$e->getMessage()."";// 获取错误码echo$e->getCode()."";// 获取出错文件名echo$e->getFile()."";// 获取出错行echo$e->getLine()."";// 把异常以字符串返回echo$e->getTraceAsString();}?>

5. 使用prepare和execute方法插入/更新数据

方法和#3中进行查询的差不多,只是构造的SQL语句是insert语句或update语句,代码如下:Php代码file:pdo-prepare-insert.php url:http://localhost:88/pdo/pdo-insert.php?title=title11 php setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);echo'connect to database successfully!'."";// 构造Insert语句$sql ="INSERT INTO blog(title) VALUES(:title)";$stmt =$dbh->prepare($sql);$stmt->bindParam(":title",$title);$stmt->execute();} catch (Exception$e) {echo'Errors occur when query data!\n';echo$e->getMessage();}?>Php代码file:pdo-prepare-update.php url:http://localhost:88/pdo/pdo-update.php?id=1&title=title12 php setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);echo'connect to database successfully!'."";// 构造update语句$sql ="UPDATE blog SET title=:title where id=:id";$stmt =$dbh->prepare($sql);$stmt->bindParam(":id",$id);$stmt->bindParam(":title",$title);$stmt->execute();} catch (Exception$e) {echo'Errors occur when query data!\n';echo$e->getMessage();}?>

6. 获取返回的行数

使用#3中的prepare和execute方法,然后将sql语句改成count的,例如SELECT COUNT(id) FROM article ...,代码如下:Php代码file:pdo-prepare-fetch-column.php url:http://localhost:88/pdo/pdo-prepare-fetch-column.php?id=1&title=title12 php setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);echo'connect to database successfully!'."";// 构造count语句$sql ="SELECT COUNT(id) FROM blog";$stmt =$dbh->prepare($sql);$stmt->execute();// 使用fetchColumn获取0列值echo$stmt->fetchColumn()." rows returned!";} catch (Exception$e) {echo'Errors occur when query data!\n';echo$e->getMessage();}?>

7. 获取受影响的行数

使用#3中的prepare和execute方法,然后将SQL语句改成insert、update、delete语句即可,代码如下:Php代码file:pdo-prepare-row-count.php url:http://localhost:88/pdo/pdo-prepare-row-count.php?id=1 php setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);echo'connect to database successfully!'."";$sql ="DELETE FROM blog WHERE id=:id";$stmt =$dbh->prepare($sql);$stmt->bindParam(":id",$id);$stmt->execute();// 获取update、insert、delete操作后影响的行数echo$stmt->rowCount()." rows affected!";} catch (Exception$e) {echo'Errors occur when data operation!\n';echo$e->getMessage();}?>

8. 获得新插入行的ID值

为数据库表插入新数据行时,我们需要获得刚刚插入的新行的ID值,此时我们需要使用到PDO的lastInsertId()方法,代码如下:Php代码file:pdo-prepare-last-insertid.php url:http://localhost:88/pdo/pdo-prepare-last-insertid.php?title=title13 php setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);echo'connect to database successfully!'."";$sql ="INSERT INTO blog(title) VALUES(:title)";$stmt =$dbh->prepare($sql);$stmt->bindParam(":title",$title);$stmt->execute();// 获取上一个之行的insert语句插入的数据的id值echo$dbh->lastInsertId();} catch (Exception$e) {echo'Errors occur when query data!\n';echo$e->getMessage();}?>

9. 使用PDO进行事务管理

事务是进行程序开发时,保证数据ACID(可分性、一致性、独立性、持久性)的工具。要不全部成功,要不全部不成功,这样才能保证关联数据的保存能够达到预期的目的。下面使用PDO的Transaction来进行实验,进行多比数据插入,开启事务,第一句sql是可以正常插入,第二句sql插入出错,检查是否rollback。

Php代码file:pdo-prepare-transaction.php url:http://localhost:88/pdo/pdo-prepare-transaction.php php setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);echo'connect to database successfully!'."";// 开启事务$dbh->beginTransaction();$sql ="INSERT INTO blog(title) VALUES(:title)";$stmt =$dbh->prepare($sql);$stmt->execute(array(':title'=>'insert title1'));$stmt->execute(array(':title'=>NULL));// 提交事务$dbh->commit();} catch (Exception$e) {echo'Errors occur when data operation!\n';echo$e->getMessage();// 回滚事务$dbh->rollBack();}?>

10. 使用PDO进行数据库备份

使用system函数,将我们构造的mysqldump命令传入即可。下面为了演示,只做了简单的调用。

Php代码file:pdo-backup.php url:http://localhost:88/pdo/pdo-backup.php php ".$file;// 执行备份命令system($cmd,$error);if($error){trigger_error("backup failed".$error);}?>

采用工厂模式:

Php代码file:AbstractMySQLDump.php php cmd,$error);// 判断是否出错及出错逻辑if($error){trigger_error("backup failure! command:".$this->cmd." Error:".$error);}}}?>Php代码file:MySQLDump_Win.php php cmd ="mysqldump -u".$username." -p".$passwd." ".$dbname." > ".$file;}}?>Php代码file:MySQLDumpTest.php url:http://localhost:88/pdo/MySQLDumpTest.php php backup();?>

相关文章