pdo借鉴

Posted 一阙梅曲香素笺

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pdo借鉴相关的知识,希望对你有一定的参考价值。

别人的

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

    PDOPHP Data Objects的简称,是一种数据库访问抽象层。PDO是用于多种数据库的一致接口。类比的说,PDO做的事情类似于JAVA中的持久层框架(HibernateOpenJPA)的功能,为异构数据库提供一个统一的编程接口,这样就不必再使用mysql_*pg_*这样的函数,也不必再写自己的"GenericDAO"了。PDOPHP5.1的时候一起发布,所以我们用的PHP5.2PHP5.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)指定dsnusernamepasswordb)通过#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. ?>  

备注:DSNData Source Name-数据源名称,提供数据库的连接信息,包括三部分,PDO驱动名称(MySQLSQLitePostgreSQL等)、冒号和驱动特定的语法。但是一般情况下,我们都很难记住这些,可以下载个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语句的方法来进行queryupdateinsertdelete,都会需要指定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),转移出来后的sqlSELECT * FROM blog WHERE title = ‘\‘OR id LIKE \‘%‘,把所有的单引号()都转移了。 

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

        使用prepareexecute方法的步骤不多,a)构造SQLb)SQL传入PDO->prepart方法,得到一个PDOStatement对象,3)调用PDOStatement对象的execute方法,4)通过PDOStatement->fetchPDOStatement->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_WARNINGPDO::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{...}进行捕捉,否则未catchexception会导致程序中断,加入以下代码即可:$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. 使用prepareexecute方法插入/更新数据 
    方法和#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中的prepareexecute方法,然后将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中的prepareexecute方法,然后将SQL语句改成insertupdatedelete语句即可,代码如下: 

  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值,此时我们需要使用到PDOlastInsertId()方法,代码如下: 

  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(可分性、一致性、独立性、持久性)的工具。要不全部成功,要不全部不成功,这样才能保证关联数据的保存能够达到预期的目的。下面使用PDOTransaction来进行实验,进行多比数据插入,开启事务,第一句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. ?>  

 

以上是关于pdo借鉴的主要内容,如果未能解决你的问题,请参考以下文章

设计专用色系,挺不错的值得借鉴

jQuery二级联动借鉴学习

我的微信学习开发-----借鉴李忠益老师

广告推荐工业借鉴

广告推荐工业借鉴

实际项目借鉴