MySQL PDO的介绍和使用

PDO一是PHP数据对象(PHP Data Object)的缩写。
并不能使用PDO扩展本身执行任何数据库操作,必须使用一个database-specific PDO driver(针对特定数据库的PDO驱动)访问数据库服务器。
PDO并不提供数据库抽象,它并不会重写SQL或提供数据库本身缺失的功能,如果你需要这种功能,你需要使用一个更加成熟的抽象层。
PDO需要PHP5核心OO特性的支持,所以它无法运行于之前的PHP版本。

一.下面首先我们介绍一下PDO的好处:

PDO有非常多的操作却是MySQL扩展库所不具备的:

1:PDO真正的以底层实现的统一接口数库操作接口,不管后端使用的是何种数据库,如果代码封装好了以后,应用层调用基本上差不多的,当后端数据库更换了以后,应用层代码基本不用修改.

2:PDO支持更高级的DB特性操作,如:存储过程的调度等,mysql原生库是不支持的.

3:PDO是PHP官方的PECL库,兼容性稳定性必然要高于MySQL Extension,可以直接使用 pecl upgrade pdo 命令升级.

4:PDO可以防止SQL注入,确保数据库更加安全(原理其实就是:PHP就是通过实现SQL模板和参数变量分两次发送给MySQL,由MYSQL完成变量的转义处理,既然变量和SQL模板是两次发送的,也就不存在SQL注入的问题了)
下面是pdo方sql注入的代码:(即pdo通过预处理防止sql注入)

<?php
$pdo = new PDO("mysql:host=192.168.0.1;dbname=test;charset=utf8","root");
$st = $pdo->prepare("select * from info where id =? and name = ?");
$id = 21;
$name = 'zhangsan';
$st->bindParam(1,$id);
$st->bindParam(2,$name);
 $st->execute();
$st->fetchAll();
?>


预处理语句
使用语句预处理将帮助你免于SQL注入攻击。

一条预处理语句是一条预编译的 SQL 语句,它可以使用多次,每次只需将数据传至服务器。其额外优势在于可以对使用占位符的数据进行安全处理,防止SQL注入攻击。

下面是未进行预处理和进行预处理的两段代码:

1.未进行预处理的代码:

  1. <?php  
  2. header('content-type:text/html;charset=utf-8');  
  3. $username=$_POST['username'];  
  4. $psw=$_POST['psw'];  
  5. try {  
  6. $pdo=new PDO('mysql:host=localhost;dbname=test','root','root');  
  7. $sql="select * from user where username='{$username}' and password='{$psw}'";  
  8. $stmt=$pdo->query($sql);  
  9. //返回结果集中的行数  
  10. echo $stmt->rowCount();  
  11. } catch (Exception $e) {  
  12. echo $e->getMessage();  
  13. }  
  14. ?>  
2.进行预处理的代码:

(占位符的使用:)

  1. <?php  
  2. header('content-type:text/html;charset=utf-8');  
  3. $username=$_POST['username'];  
  4. $psw=$_POST['psw'];  
  5.     try {  
  6.         $pdo=new PDO('mysql:host=localhost;dbname=test','root','root');  
  7.         $sql="select * from user where username=:username and password=:psw";  
  8.         $stmt=$pdo->prepare($sql);  
  9.         $stmt->execute(array(":username"=>$username,":psw"=>$psw));  
  10.         echo $stmt->rowCount();  
  11.     } catch (Exception $e) {  
  12.         echo $e->getMessage();  
  13.     }  
  14. ?>  
或:

  1. <?php  
  2. header('content-type:text/html;charset=utf-8');  
  3. $username=$_POST['username'];  
  4. $psw=$_POST['psw'];  
  5.     try {  
  6.         $pdo=new PDO('mysql:host=localhost;dbname=test','root','root');  
  7.         $sql="select * from user where username=? and password=?";  
  8.         $stmt=$pdo->prepare($sql);  
  9.         $stmt->execute(array($username,$psw));  
  10.         echo $stmt->rowCount();  
  11.     } catch (Exception $e) {  
  12.         echo $e->getMessage();  
  13.     }  
  14. ?>  


5.根据PHP官方计划,PHP6正式到来之时,数据库链接方式统一为PDO。但是总有一小撮顽固分子,趁PHP官方还没正式统一时,还用老式的MYSQL驱动链接数据库。即使现在有部分程序改用Mysqli/pdo,只要没用到预编译,均和老式的Mysql驱动没多大区别。在此,我就不点评国内的PHP生态环境了。
回归主题,为什么说PHP必须要用PDO?除了官方要求之外,我认为作为PHP程序员,只要你目前是做开发的话,那么请选择用PDO的程序/框架!PDO除了安全和万金油式数据库链接,还有一点是我目前觉得非常好用的!下面我就用我最近的切身体会来说。
业务环境:公司某老架构,数据库设计的人员太菜了,设计过程完全没有按照数据库范式进行。各种表中使用大量的序列化形式保存(补充:json同理)。
出现问题:销售的客服反馈,网站某用户在编辑地址时,Mysql报错了。
问题猜想:不用说了。肯定是引号,反斜杠引起序列化入库不正常。

http://zhidao.baidu.com/question/1541430860923158627


6.安装配置及测试
在windows下进行有关pdo测试的时候,php.ini中的extension_dir的值要填为pdo*.dll的路径,否则无法运行pdo的相关程序。
; Directory in which the loadable extensions (modules) reside.
extension_dir = "E:\www\php5\ext"

 

下面是一段PDO使用的代码,可以看一下:

复制代码
  1 <?php
  2 $host = 'localhost';
  3 $user = 'root';
  4 $password = 'develop';
  5 $dbname = '99game';
  6 
  7 $dbh = new PDO("mysql:host=$host;dbname=$dbname", $user, $password); 
  8 
  9 //=======================================================
 10 //例子 1. Execute a prepared statement with named placeholders
 11 /* Execute a prepared statement by binding PHP variables */
 12 $user_id = 1;
 13 $email = 'caihf_73940@qq.com';
 14 $sth = $dbh->prepare('SELECT user_id,email,token FROM 99game_user 
 15     WHERE user_id = :user_id AND email = :email');
 16 $sth->bindParam(':user_id', $user_id, PDO::PARAM_INT);
 17 $sth->bindParam(':email', $email, PDO::PARAM_STR, 30);
 18 $sth->execute();  
 19 $result = $sth->fetch(PDO::FETCH_ASSOC);
 20 print_r($result);
 21 print("<br />\n");
 22 
 23 //例子 2. Execute a prepared statement with question mark placeholders
 24 /* Execute a prepared statement by binding PHP variables */
 25 $user_id = 2;
 26 $email = 'caihuafeng1@gmail.com';
 27 $sth = $dbh->prepare('SELECT user_id,email,token FROM 99game_user 
 28     WHERE user_id = ? AND email = ?');
 29 $sth->bindParam(1, $user_id, PDO::PARAM_INT);
 30 $sth->bindParam(2, $email, PDO::PARAM_STR, 30);
 31 $sth->execute();
 32 $result = $sth->fetch(PDO::FETCH_ASSOC);
 33 print_r($result);
 34 print("<br />\n");
 35 
 36 print "<hr />\n";
 37  //=======================================================
 38 
 39 //=======================================================
 40 $sth = $dbh->prepare("SELECT user_id,email,token FROM 99game_user limit 10");
 41 $sth->execute();
 42 
 43 /* 运用 PDOStatement::fetch 风格 */
 44 print("PDO::FETCH_ASSOC: ");
 45 print("Return next row as an array indexed by column name<br />\n");
 46 $result = $sth->fetch(PDO::FETCH_ASSOC);
 47 print_r($result);
 48 print("<br />\n");
 49 print("\n");
 50 
 51 print("PDO::FETCH_BOTH: ");
 52 print("Return next row as an array indexed by both column name and number<br />\n");
 53 $result = $sth->fetch(PDO::FETCH_BOTH);
 54 print_r($result);
 55 print("<br />\n");
 56 print("\n");
 57 
 58 print("PDO::FETCH_LAZY: ");
 59 print("Return next row as an anonymous object with column names as properties<br />\n");
 60 $result = $sth->fetch(PDO::FETCH_LAZY);
 61 print_r($result);
 62 print("<br />\n");
 63 print("\n");
 64 
 65 print("PDO::FETCH_OBJ: ");
 66 print("Return next row as an anonymous object with column names as properties<br />\n");
 67 $result = $sth->fetch(PDO::FETCH_OBJ);
 68 print_r($result);
 69 print 'user_id:' . $result->user_id;
 70 print("<br />\n");
 71 print("\n");
 72 
 73 print "<hr />\n";
 74 //=======================================================
 75 
 76 //=======================================================
 77 function readDataForwards($dbh) {
 78   $sql = 'SELECT user_id,email,token FROM 99game_user limit 10';
 79   try {
 80     $stmt = $dbh->prepare($sql, array(PDO::ATTR_CURSOR, PDO::CURSOR_SCROLL));
 81     $stmt->execute();
 82     while ($row = $stmt->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_NEXT)) {
 83       $data = $row[0] . "\t" . $row[1] . "\t" . $row[2] . "<br />\n";
 84       print $data;
 85     }
 86     $stmt = null;
 87   }
 88   catch (PDOException $e) {
 89     print $e->getMessage();
 90   }
 91 }
 92 
 93 function readDataBackwards($dbh) {
 94   $sql = 'SELECT user_id,email,token FROM 99game_user limit 10';
 95   try {
 96     $stmt = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
 97     $stmt->execute();
 98     $row = $stmt->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_LAST);
 99     do {
100       $data = $row[0] . "\t" . $row[1] . "\t" . $row[2] . "<br />\n";
101       print $data;
102     } while ($row = $stmt->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_PRIOR));
103     $stmt = null;
104   }
105   catch (PDOException $e) {
106     print $e->getMessage();
107   }
108 }
109 
110 print "Reading forwards:<br />\n";
111 readDataForwards($dbh);
112 
113 print "<hr />\n";
114 
115 print "Reading backwards:<br />\n";
116 //下面的数据没有按照想像中的倒排输出,暂时不知道什么原因,php.net官方手册中的例子也是这么写的
117 readDataBackwards($dbh);
118 //=======================================================
119 ?>


<?php 
$dbh = new PDO('mysql:host=localhost;dbname=access_control', 'root', '');  
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  
$dbh->exec('set names utf8');  
/*添加*/ 
//$sql = "INSERT INTO `user` SET `login`=:login AND `password`=:password";  
$sql = "INSERT INTO `user` (`login` ,`password`)VALUES (:login, :password)"; $stmt = $dbh->prepare($sql); $stmt->execute(array(':login'=>'kevin2',':password'=>''));  
echo $dbh->lastinsertid();  
/*修改*/ 
$sql = "UPDATE `user` SET `password`=:password WHERE `user_id`=:userId";  
$stmt = $dbh->prepare($sql);  
$stmt->execute(array(':userId'=>'7', ':password'=>'4607e782c4d86fd5364d7e4508bb10d9'));  
echo $stmt->rowCount();  
/*删除*/ 
$sql = "DELETE FROM `user` WHERE `login` LIKE 'kevin_'"; //kevin%  
$stmt = $dbh->prepare($sql);  
$stmt->execute();  
echo $stmt->rowCount();  
/*查询*/ 
$login = 'kevin%';  
$sql = "SELECT * FROM `user` WHERE `login` LIKE :login";  
$stmt = $dbh->prepare($sql);  
$stmt->execute(array(':login'=>$login));  
while($row = $stmt->fetch(PDO::FETCH_ASSOC)){    
 print_r($row);  
}  
print_r( $stmt->fetchAll(PDO::FETCH_ASSOC));  
?> 

1 建立连接


<?php 
$dbh=newPDO('mysql:host=localhost;port=3306; dbname=test',$user,$pass,array( 
PDO::ATTR_PERSISTENT=>true 
)); 
?> 

持久性链接PDO::ATTR_PERSISTENT=>true

2. 捕捉错误


<?php 
try{ 
$dbh=newPDO('mysql:host=localhost;dbname=test',$user,$pass); 
 
$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); 
 
$dbh->exec("SET CHARACTER SET utf8"); 
$dbh=null; //断开连接 
}catch(PDOException$e){ 
print"Error!:".$e->getMessage()."<br/>"; 
die(); 
} 
?> 

3. 事务的


<?php 
try{ 
$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); 
 
$dbh->beginTransaction();//开启事务 
$dbh->exec("insertintostaff(id,first,last)values(23,'Joe','Bloggs')"); 
$dbh->exec("insertintosalarychange(id,amount,changedate) 
values(23,50000,NOW())"); 
$dbh->commit();//提交事务 
 
}catch(Exception$e){ 
$dbh->rollBack();//错误回滚 
echo"Failed:".$e->getMessage(); 
} 
?> 

4. 错误处理

a. 静默模式(默认模式)


$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_SILENT); //不显示错误
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);//显示警告错误,并继续执行
$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);//产生致命错误,PDOException

<?php 
try{   
 $dbh = new PDO($dsn, $user, $password);   
 $sql = 'Select * from city where CountryCode =:country';   
 $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);   
 $stmt = $dbh->prepare($sql);   
 $stmt->bindParam(':country', $country, PDO::PARAM_STR);   
 $stmt->execute();   
 while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {    
 print $row['Name'] . "/t";   
 }  
}  // if there is a problem we can handle it here  
catch (PDOException $e) {   
 echo 'PDO Exception Caught. ';   
 echo 'Error with the database: <br />';   
 echo 'SQL Query: ', $sql;   
 echo 'Error: ' . $e->getMessage();  
}  
?> 

1. 使用 query()


<?php 
$dbh->query($sql); 当$sql 中变量可以用$dbh->quote($params); //转义字符串的数据 
 
$sql = 'Select * from city where CountryCode ='.$dbh->quote($country);  
foreach ($dbh->query($sql) as $row)  {   
 print $row['Name'] . "/t";   
 print $row['CountryCode'] . "/t";   
 print $row['Population'] . "/n";  
}  
?> 

2. 使用 prepare, bindParam和 execute [建议用,同时可以用添加、修改、删除]


<?php 
$dbh->prepare($sql); 产生了个PDOStatement对象 
 
PDOStatement->bindParam() 
 
PDOStatement->execute();//可以在这里放绑定的相应变量 
?> 

3. 事物


<?php  
 try {  
 $dbh = new PDO('mysql:host=localhost;dbname=test', 'root', '');  
 $dbh->query('set names utf8;');  
 $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  
 $dbh->beginTransaction();  
 $dbh->exec("Insert INTO `test`.`table` (`name` ,`age`)VALUES ('mick', 22);");  
 $dbh->exec("Insert INTO `test`.`table` (`name` ,`age`)VALUES ('lily', 29);");  
 $dbh->exec("Insert INTO `test`.`table` (`name` ,`age`)VALUES ('susan', 21);");  
 $dbh->commit();  
 } catch (Exception $e) {  
 $dbh->rollBack();  
 echo "Failed: " . $e->getMessage();  
 }  
?>  

PDO常用方法:

PDO::query()主要用于有记录结果返回的操作(PDOStatement),特别是select操作。
PDO::exec()主要是针对没有结果集合返回的操作。如insert,update等操作。返回影响行数。
PDO::lastInsertId()返回上次插入操作最后一条ID,但要注意:如果用insert into tb(col1,col2) values(v1,v2),(v11,v22)..的方式一次插入多条记录,lastinsertid()返回的只是第一条(v1,v2)插入时的ID,而不是最后一条记录插入的记录ID。
PDOStatement::fetch()是用来获取一条记录。配合while来遍历。
PDOStatement::fetchAll()是获取所有记录集到一个中。
PDOStatement::fetchcolumn([int column_indexnum])用于直接访问列,参数column_indexnum是该列在行中的从0开始索引值,但是,这个方法一次只能取得同一行的一列,只要执行一次,就跳到下一行。因此,用于直接访问某一列时较好用,但要遍历多列就用不上。
PDOStatement::rowcount()适用于当用query("select ...")方法时,获取记录的条数。也可以用于预处理中。$stmt->rowcount();
PDOStatement::columncount()适用于当用query("select ...")方法时,获取记录的列数。

注解:

1、选fetch还是fetchall?

小记录集时,用fetchall效率高,减少从数据库检索次数,但对于大结果集,用fetchall则给系统带来很大负担。数据库要向WEB前端传输量太大反而效率低。

2、fetch()或fetchall()有几个参数:


mixed pdostatement::fetch([int fetch_style [,int cursor_orientation [,int cursor_offset]]])
array pdostatement::fetchAll(int fetch_style)

fetch_style参数:

■$row=$rs->fetchAll(PDO::FETCH_BOTH); FETCH_BOTH是默认的,可省,返回关联和索引。
■$row=$rs->fetchAll(PDO::FETCH_ASSOC); FETCH_ASSOC参数决定返回的只有关联数组。
■$row=$rs->fetchAll(PDO::FETCH_NUM); 返回索引数组
■$row=$rs->fetchAll(PDO::FETCH_OBJ); 如果fetch()则返回对象,如果是fetchall(),返回由对象组成的二维数组

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值