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. 建立实验环境数据库及相关表

  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 \‘%‘,把所有的单引号(‘)都转移了。

  1. 使用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. ?>
  26. 使用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. ?>
时间: 2024-08-01 22:38:55

pdo借鉴的相关文章

《细说PHP》第四版 样章 第18章 数据库抽象层PDO 2

18.2  PDO所支持的数据库 使用PHP可以处理各种数据库系统,包括MySQL.PostgreSQL.Oracle.MsSQL等.但访问不同的数据库系统时,其所使用的PHP扩展函数也是不同的.例如,使用PHP的MySQL或MySQLi扩展函数,只能访问MySQL数据库:如果需要处理Oracle数据库,就必须安装和重新学习PHP中处理Oracle的扩展函数库,每种数据库都有对应的扩展函数,如图18-3所示.应用每种数据库时都需要学习特定的函数库,这样是比较麻烦的,更重要的是这使得数据库间的移植

PHP wget 增强脱裤脚本(PDO MYSQL)

脚本参考了 LCX Gavin2位前辈的帖子.在此表示非常的感谢. https://www.t00ls.net/thread-26740-1-1.html https://www.t00ls.net/thread-26791-1-1.html 说明:脚本支持PDO和MYSQL 2种方式 优先使用PDO .如果服务器不支持PDO  就选择MYSQL 方式. 个人认为  PDO 的好处有效率高  代码简洁 通用性好  这代码稍作改动就可以拿去脱mssql 不过用php和mssql组合的应该不多- -

运用PDO存储将图片、音频文件存入数据库

在数据库中创建表格的时候,有一个字段为image,用来保存图片,那么其类型就是blob,关于blob,百度百科是这样描述的 BLOB (binary large object),二进制大对象,是一个可以存储二进制文件的容器. 在计算机中,BLOB常常是数据库中用来存储二进制文件的字段类型. BLOB是一个大文件,典型的BLOB是一张图片或一个声音文件,由于它们的尺寸,必须使用特殊的方式来处理(例如:上传.下载或者存放到一个数据库). 根据Eric Raymond的说法,处理BLOB的主要思想就是

数据库的事务处理---PDO实现

事务处理用一句简单的术语称为"原子操作",即一件事情,要么全部完成,要么一个也别完成:有一种一荣俱荣,一损俱损的感觉. 最常用的就是在交易过程中,比如在网络中,甲方付费给乙方,钱确认付款,但是乙方并未确认收款,那么,甲方的账户并不会减少,乙方的账户也并不会增加. 只有当甲方确认付款,乙方确认收款,两个步骤都完成,并且不出现错误的时候,双方的账户才会改变 看代码也许更好理解 1 <?php 2 try{ 3 $pdo=new PDO("mysql:host=localho

调用cmd命令行命令(借鉴)

留待以后观看 ---------------------------------------------------------------------------- public class IP_MAC_TypeHelper { /** * 控制台执行arp -a命令 * * @return * */ public static InputStream getInputStream() { Runtime rt = Runtime.getRuntime(); InputStream in =

PHP面向对象之php数据对象(PDO)——图书查看管理

首先创建相关的有关的数据库:数据库的名字我用的是books表名用的是book(下面是完整的数据库,里面的img/img01.jpg是显示的图片的路径) CREATE DATABASE books DEFAULT CHARSET=utf8;USE books; CREATE TABLE book( b_id INT PRIMARY KEY AUTO_INCREMENT, b_name VARCHAR(100) NOT NULL UNIQUE, b_img VARCHAR(50) NOT NULL,

PHP中PDO的配置与说明

住[PDO是啥] PDO是PHP5新加入的一个重大功能,因为在PHP5以前的php4/php3都是一堆的数据库扩展来跟各个数据库的连接和处理,什么php_mysql.dll.php_pgsql.dll.php_mssql.dll.php_sqlite.dll等等扩展来连接MySQL.PostgreSQL.MSSQLServer.SQLite,同样的,我们必须借助ADOdb.PEAR:B.PHPlib:B之类的数据库抽象类来帮助我们,无比烦琐和低效,毕竟,php代码的效率怎么能够我们直接用C/C+

PHP中MySQL、MySQLi和PDO的用法和区别【原创】

对于一个初学PHP的自己,对数据库的连接有着很大的疑惑,从Java转到PHP.数据库连接变了,以前只知道JDBC连接数据库,或者直接用框架调用,对于的PHP的数据库连接方式,及其应用.不是很了解,于是查阅了很多资料及自己实际操作,写下自己的一点总结笔记. PHP的MySQL扩展(优缺点) 设计开发允许PHP应用与MySQL数据库交互的早期扩展.mysql扩展提供了一个面向过程 的接口: 并且是针对MySQL4.1.3或更早版本设计的.因此,这个扩展虽然可以与MySQL4.1.3或更新的数 : 据

PHP:PDO prepare预处理

许多成熟的数据库都支持预处理语句(Prepared Statements)的概念.它们是什么东西?你可以把它们想成是一种编译过的要执行的SQL语句模板,可以使用不同的变量参数定制它.预处理语句具有两个主要的优点: 查询只需要被解析(或准备)一次,但可以使用相同或不同的参数执行多次.当查询准备好(Prepared)之后,数据库就会分析,编译并优化它要执行查询的计划.对于复杂查询来说,如果你要重复执行许多次有不同参数的但结构相同的查询,这个过程会占用大量的时间,使得你的应用变慢.通过使用一个预处理语