之前一段时间,开始了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. 建立实验环境数据库及相关表

  1. CREATE TABLE `blog` (
  2. `id` int(10) NOT NULL AUTO_INCREMENT,
  3. `title` varchar(255) NOT NULL,
  4. PRIMARY KEY (`id`)
  5. ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=latin1

1. 使用PDO访问数据库 
    通过PDO访问数据库的步骤是:a)指定dsn、username、password,b)通过#a中的设置构造PDO对象,代码如下:

  1. file:pdo-access.php
  2. url:http://localhost:88/pdo/pdo-access.php
  3. <?php
  4. // 设置dsn、username、passwd
  5. $dsn = 'mysql:host=localhost;dbname=pdotest';
  6. $username = 'root';
  7. $passwd = 'password';
  8. // 构造PDO对象
  9. try {
  10. $dbh = new PDO($dsn, $username, $passwd);
  11. echo 'connect to database successfully!';
  12. } catch (Exception $e) {
  13. echo 'Fail to connect to database!\n';
  14. echo $e->getMessage();
  15. }
  16. ?>

    备注:DSN即Data Source Name-数据源名称,提供数据库的连接信息,包括三部分,PDO驱动名称(MySQL、SQLite、PostgreSQL等)、冒号和驱动特定的语法。但是一般情况下,我们都很难记住这些,可以下载个php manual查,也可以到php的官网查。

2. 使用Query方法查询数据 
    在#1的基础上,连接数据库成功后,构造SQL语句,调用query方法返回结构数组,通过foreach进行数据结果遍历,代码如下:

  1. file:pdo-query.php
  2. url:http://localhost:88/pdo/pdo-query.php?title=title1
  3. <?php
  4. $dsn = 'mysql:host=localhost;dbname=pdotest';
  5. $username = 'root';
  6. $passwd = 'password';
  7. try {
  8. $dbh = new PDO($dsn, $username, $passwd);
  9. echo 'connect to database successfully!'."\r\n";
  10. $title = 'title1';
  11. // 构造SQL语句
  12. $sql = "SELECT * FROM blog WHERE title = '".$title."'";
  13. // 执行查询并遍历结果
  14. foreach ($dbh->query($sql) as $row){
  15. print $row['id']."\t";
  16. print $row['title']."\t";
  17. }
  18. } catch (PDOException $e) {
  19. echo 'Errors occur when query data!\n';
  20. echo $e->getMessage();
  21. }
  22. ?>

    备注:一般情况下, 通过构造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遍历结果集。代码如下:

  1. file:pdo-prepare-fetch.php
  2. url:http://localhost:88/pdo/pdo-prepare-fetch.php?title=title1
  3. <?php
  4. $dsn = 'mysql:host=localhost;dbname=pdotest';
  5. $username = 'root';
  6. $passwd = 'password';
  7. // 从请求获取title参数值
  8. $title = $_GET['title'];
  9. try {
  10. $dbh = new PDO($dsn, $username, $passwd);
  11. echo 'connect to database successfully!'."<br/>";
  12. // 构造SQL语句,使用绑定变量
  13. $sql = "SELECT * FROM blog WHERE title = :title";
  14. // 编译SQL
  15. $stmt = $dbh->prepare($sql);
  16. // 为绑定变量赋值
  17. $stmt->bindParam(":title", $title, PDO::PARAM_STR);
  18. // 执行SQL
  19. $stmt->execute();
  20. // 以联合数组方式获取结果,并遍历结果
  21. while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
  22. print $row['id']."\t";
  23. print $row['title']."\t";
  24. }
  25. } catch (PDOException $e) {
  26. echo 'Errors occur when query data!\n';
  27. echo $e->getMessage();
  28. }
  29. ?>

除了使用上面的PDO::FETCH_ASSOC返回联合数组外,还可以使用fetchObject方法,返回结果集对象,代码如下:

  1. file:pdo-prepare-fetch-object.php
  2. url:http://localhost:88/pdo/pdo-prepare-fetch-object.php?title=title1
  3. <?php
  4. $dsn = 'mysql:host=localhost;dbname=pdotest';
  5. $username = 'root';
  6. $passwd = 'password';
  7. $title = $_GET['title'];
  8. try {
  9. $dbh = new PDO($dsn, $username, $passwd);
  10. echo 'connect to database successfully!'."<br/>";
  11. $sql = "SELECT * FROM blog WHERE title = :title";
  12. $stmt = $dbh->prepare($sql);
  13. $stmt->bindParam(":title", $title, PDO::PARAM_STR);
  14. $stmt->execute();
  15. // 以对象数组方式获取结果,并遍历结果
  16. while ($row = $stmt->fetchObject()) {
  17. print $row->id."\t";
  18. print $row->title."\t";
  19. }
  20. } catch (Exception $e) {
  21. echo 'Errors occur when query data!\n';
  22. echo $e->getMessage();
  23. }
  24. ?>

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);

  1. <?php
  2. ...
  3. try {
  4. ...
  5. } catch (Exception $e) {
  6. echo 'Errors occur when operation!'."<br/>";
  7. // 获取Exception信息
  8. echo $e->getMessage()."<br/>";
  9. // 获取错误码
  10. echo $e->getCode()."<br/>";
  11. // 获取出错文件名
  12. echo $e->getFile()."<br/>";
  13. // 获取出错行
  14. echo $e->getLine()."<br/>";
  15. // 把异常以字符串返回
  16. echo $e->getTraceAsString();
  17. }
  18. ?>

5. 使用prepare和execute方法插入/更新数据 
    方法和#3中进行查询的差不多,只是构造的SQL语句是insert语句或update语句,代码如下:

  1. file:pdo-prepare-insert.php
  2. url:http://localhost:88/pdo/pdo-insert.php?title=title11
  3. <?php
  4. $dsn = 'mysql:host=localhost;dbname=pdotest';
  5. $username = 'root';
  6. $passwd = 'password';
  7. $title = $_GET['title'];
  8. try {
  9. $dbh = new PDO($dsn, $username, $passwd);
  10. $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  11. echo 'connect to database successfully!'."<br/>";
  12. // 构造Insert语句
  13. $sql = "INSERT INTO blog(title) VALUES(:title)";
  14. $stmt = $dbh->prepare($sql);
  15. $stmt->bindParam(":title", $title);
  16. $stmt->execute();
  17. } catch (Exception $e) {
  18. echo 'Errors occur when query data!\n';
  19. echo $e->getMessage();
  20. }
  21. ?>
  1. file:pdo-prepare-update.php
  2. url:http://localhost:88/pdo/pdo-update.php?id=1&title=title12
  3. <?php
  4. $dsn = 'mysql:host=localhost;dbname=pdotest';
  5. $username = 'root';
  6. $passwd = 'password';
  7. $id = $_GET['id'];
  8. $title = $_GET['title'];
  9. try {
  10. $dbh = new PDO($dsn, $username, $passwd);
  11. $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  12. echo 'connect to database successfully!'."<br/>";
  13. // 构造update语句
  14. $sql = "UPDATE blog SET title=:title where id=:id";
  15. $stmt = $dbh->prepare($sql);
  16. $stmt->bindParam(":id", $id);
  17. $stmt->bindParam(":title", $title);
  18. $stmt->execute();
  19. } catch (Exception $e) {
  20. echo 'Errors occur when query data!\n';
  21. echo $e->getMessage();
  22. }
  23. ?>

6. 获取返回的行数 
    使用#3中的prepare和execute方法,然后将sql语句改成count的,例如SELECT COUNT(id) FROM article ...,代码如下:

  1. file:pdo-prepare-fetch-column.php
  2. url:http://localhost:88/pdo/pdo-prepare-fetch-column.php?id=1&title=title12
  3. <?php
  4. $dsn = 'mysql:host=localhost;dbname=pdotest';
  5. $username = 'root';
  6. $passwd = 'password';
  7. try {
  8. $dbh = new PDO($dsn, $username, $passwd);
  9. $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
  10. echo 'connect to database successfully!'."<br/>";
  11. // 构造count语句
  12. $sql = "SELECT COUNT(id) FROM blog";
  13. $stmt = $dbh->prepare($sql);
  14. $stmt->execute();
  15. // 使用fetchColumn获取0列值
  16. echo $stmt->fetchColumn()." rows returned!";
  17. } catch (Exception $e) {
  18. echo 'Errors occur when query data!\n';
  19. echo $e->getMessage();
  20. }
  21. ?>

7. 获取受影响的行数 
    使用#3中的prepare和execute方法,然后将SQL语句改成insert、update、delete语句即可,代码如下:

  1. file:pdo-prepare-row-count.php
  2. url:http://localhost:88/pdo/pdo-prepare-row-count.php?id=1
  3. <?php
  4. $dsn = 'mysql:host=localhost;dbname=pdotest';
  5. $username = 'root';
  6. $passwd = 'password';
  7. $id = $_GET['id'];
  8. try {
  9. $dbh = new PDO($dsn, $username, $passwd);
  10. $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
  11. echo 'connect to database successfully!'."<br/>";
  12. $sql = "DELETE FROM blog WHERE id=:id";
  13. $stmt = $dbh->prepare($sql);
  14. $stmt->bindParam(":id", $id);
  15. $stmt->execute();
  16. // 获取update、insert、delete操作后影响的行数
  17. echo $stmt->rowCount()." rows affected!";
  18. } catch (Exception $e) {
  19. echo 'Errors occur when data operation!\n';
  20. echo $e->getMessage();
  21. }
  22. ?>

8. 获得新插入行的ID值 
    为数据库表插入新数据行时,我们需要获得刚刚插入的新行的ID值,此时我们需要使用到PDO的lastInsertId()方法,代码如下:

  1. file:pdo-prepare-last-insertid.php
  2. url:http://localhost:88/pdo/pdo-prepare-last-insertid.php?title=title13
  3. <?php
  4. $dsn = 'mysql:host=localhost;dbname=pdotest';
  5. $username = 'root';
  6. $passwd = 'password';
  7. $title = $_GET['title'];
  8. try {
  9. $dbh = new PDO($dsn, $username, $passwd);
  10. $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  11. echo 'connect to database successfully!'."<br/>";
  12. $sql = "INSERT INTO blog(title) VALUES(:title)";
  13. $stmt = $dbh->prepare($sql);
  14. $stmt->bindParam(":title", $title);
  15. $stmt->execute();
  16. // 获取上一个之行的insert语句插入的数据的id值
  17. echo $dbh->lastInsertId();
  18. } catch (Exception $e) {
  19. echo 'Errors occur when query data!\n';
  20. echo $e->getMessage();
  21. }
  22. ?>

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

  1. file:pdo-prepare-transaction.php
  2. url:http://localhost:88/pdo/pdo-prepare-transaction.php
  3. <?php
  4. $dsn = 'mysql:host=localhost;dbname=pdotest';
  5. $username = 'root';
  6. $passwd = 'password';
  7. try {
  8. $dbh = new PDO($dsn, $username, $passwd);
  9. $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  10. echo 'connect to database successfully!'."<br/>";
  11. // 开启事务
  12. $dbh->beginTransaction();
  13. $sql = "INSERT INTO blog(title) VALUES(:title)";
  14. $stmt = $dbh->prepare($sql);
  15. $stmt->execute(array(':title'=>'insert title1'));
  16. $stmt->execute(array(':title'=>NULL));
  17. // 提交事务
  18. $dbh->commit();
  19. } catch (Exception $e) {
  20. echo 'Errors occur when data operation!\n';
  21. echo $e->getMessage();
  22. // 回滚事务
  23. $dbh->rollBack();
  24. }
  25. ?>

10. 使用PDO进行数据库备份 
    使用system函数,将我们构造的mysqldump命令传入即可。下面为了演示,只做了简单的调用。

  1. file:pdo-backup.php
  2. url:http://localhost:88/pdo/pdo-backup.php
  3. <?php
  4. $username="root";
  5. $passwd="password";
  6. $dbname="pdotest";
  7. $file='d:/'.$dbname.'.sql';
  8. // 构造备份命令
  9. $cmd = "mysqldump -u".$username." -p".$passwd." ".$dbname." >".$file;
  10. // 执行备份命令
  11. system($cmd,$error);
  12. if($error){
  13. trigger_error("backup failed".$error);
  14. }
  15. ?>

采用工厂模式:

  1. file:AbstractMySQLDump.php
  2. <?php
  3. require_once 'MySQLDump_Win.php';
  4. abstract class AbstractMySQLDump {
  5. protected $cmd;
  6. abstract function __construct($username, $passwd, $dbname, $file);
  7. // 依据操作系统类型,使用工厂方法构造备份类
  8. public static function factory($username, $passwd, $dbname, $file){
  9. if(strtoupper(substr(PHP_OS, 0, 3))==='WIN'){
  10. return new MySQLDump_Win($username, $passwd, $dbname, $file);
  11. }else{
  12. //              implement MySQLDump_NIX($username, $passwd, $dbname, $file);
  13. }
  14. }
  15. // 备份逻辑
  16. public function backup(){
  17. system($this->cmd, $error);
  18. // 判断是否出错及出错逻辑
  19. if($error){
  20. trigger_error("backup failure! command:".$this->cmd." Error:".$error);
  21. }
  22. }
  23. }
  24. ?>
  1. file:MySQLDump_Win.php
  2. <?php
  3. class MySQLDump_Win extends AbstractMySQLDump {
  4. // 覆盖父类的构造方法
  5. public function __construct($username, $passwd, $dbname, $file){
  6. $this->cmd = "mysqldump -u".$username." -p".$passwd." ".$dbname." > ".$file;
  7. }
  8. }
  9. ?>
    1. file:MySQLDumpTest.php
    2. url:http://localhost:88/pdo/MySQLDumpTest.php
    3. <?php
    4. require_once 'AbstractMySQLDump.php';
    5. $username = "root";
    6. $passwd = "password";
    7. $dbname = "pdotest";
    8. $file = "d:/".$dbname.".sql";
    9. // 使用工厂方法生成备份类
    10. $dump = AbstractMySQLDump::factory($username, $passwd, $dbname, $file);
    11. // 执行备份类的backup方法
    12. $dump->backup();
    13. ?>

php 中关于pdo的使用的更多相关文章

  1. PHP程序中使用PDO对象实现对数据库的增删改查操作的示例代码

    PHP程序中使用PDO对象实现对数据库的增删改查操作(PHP+smarty) dbconn.php <?php //------------------------使用PDO方式连接数据库文件- ...

  2. php中的PDO函数库详解

    PHP中的PDO函数库详解 PDO是一个“数据库访问抽象层”,作用是统一各种数据库的访问接口,与mysql和mysqli的函数库相比,PDO让跨数据库的使用更具有亲和力:与ADODB和MDB2相比,P ...

  3. 在php中连接数据库 pdo

    在php中连接数据库 pdo //数据库信息 $mysql_conf = array( 'host' => '127.0.0.1', 'db' => 'meteorolog_foreign ...

  4. PHP中使用PDO操作事务的一些小测试

    关于事务的问题,我们就不多解释了,以后在学习 MySQL 的相关内容时再深入的了解.今天我们主要是对 PDO 中操作事务的一些小测试,或许能发现一些比较好玩的内容. 在 MyISAM 上使用事务会怎么 ...

  5. PHP中关于PDO的使用

    执行没有结果集的查询 执行INSERT,UPDATE,DELETE的时候,不返回结果集.这个时候可以是有exec(),exec()将返回查询所影响的行数 int PDO::exec ( string ...

  6. PHP5中使用PDO连接数据库的方法

    PDO(PHP Data Object) 是PHP 中加入的东西,是PHP 5新加入的一个重大功能,因为在PHP 5以前的php4/php3都是一堆的数据库扩展来跟各个数据库的连接和处理,php_my ...

  7. PHP中关于PDO数据访问抽象层的功能操作

    PDO:数据访问抽象层 具有三大特点: 1.可以访问其它数据库  所有数据库都可以 2.具有事务功能 3.带有预处理语句功能(防止SQL注入攻击) 实例操作代码如下: <?php //1.造PD ...

  8. PHP中的PDO数据对象

    PDO: PHP Data Object:php的数据对象.pdo是数据库操作工具类!1,它能操作很多种数据库,比如mysql,oracle,sybase....2,它具有操作数据库的更多的功能,比如 ...

  9. PHP中的PDO操作学习(四)查询结构集

    关于 PDO 的最后一篇文章,我们就以查询结果集的操作为结束.在数据库的操作中,查询往往占的比例非常高.在日常的开发中,大部分的业务都是读多写少型的业务,所以掌握好查询相关的操作是我们学习的重要内容. ...

随机推荐

  1. 【PTA 天梯赛】L3-003 社交集群(并查集)

    当你在社交网络平台注册时,一般总是被要求填写你的个人兴趣爱好,以便找到具有相同兴趣爱好的潜在的朋友.一个“社交集群”是指部分兴趣爱好相同的人的集合.你需要找出所有的社交集群. 输入格式: 输入在第一行 ...

  2. es6之扩展运算符 三个点(...)

    对象的扩展运算符理解对象的扩展运算符其实很简单,只要记住一句话就可以: 对象中的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中 let bar = { a: 1, b: 2 ...

  3. restframework序列化字段和字段构造方式

  4. c++读取ini的Section节名

    // ConsoleApplication1.cpp : 定义控制台应用程序的入口点.// #include "stdafx.h"#include "iostream&q ...

  5. HBase(3)-安装与Shell操作

    一. 安装 1. 启动Zookeeper集群 2. 启动Hadoop集群 3. 上传并解压HBase -bin.tar.gz -C /opt/module 4. 修改配置文件 #修改habse-env ...

  6. vs2013发布网站合并程序是出错(ILmerge.merge:error)

    Vs2013发布网站时,生成错误提示: 合并程序集时出错: ILMerge.Merge: ERROR!!: Duplicate type 'manage_ForcePasswrod' found in ...

  7. 20155207 2016-2017-2《Java程序设计》课程总结

    20155207 2016-2017-2<Java程序设计>课程总结 每周作业链接汇总: 预备作业一:一路风景---我期待的是师生关系 预备作业二:学习情况的相关调查 预备作业三:安装虚拟 ...

  8. 20155209 2016-2017-2 《Java程序设计》第十周学习总结

    20155209 2016-2017-2 <Java程序设计>第十周学习总结 教材学习内容总结 计算机网络,是指分布在不同地理区域的计算机用通信线路互连起来的一个具有强大功能的网络系统.网 ...

  9. 20155337 《Java程序设计》实验一(Java开发环境的熟悉)实验报告

    20155337 <Java程序设计>实验一(Java开发环境的熟悉)实验报告 一.实验内容及步骤 (一)使用JDK编译.运行简单的java程序 ·命令行下的程序开发 我在windows下 ...

  10. 优步uber司机申请了为什么一直没有通过审核,帐号也显示未激活

    优步uber现在是越来越火,申请注册成为优步uber司机的人数也日剧增多,申请了的车主都知道,申请后要等待审核,审核通过才可以激活帐号,快的运气好的,三五天不到一个星期就激活了,慢点的得大半个月,还有 ...