Selecting Data
你在mysql_*中是这样做的
1 <?php 2 $result = mysql_query('SELECT * from table') or die(mysql_error()); 3 4 $num_rows = mysql_num_rows($result); 5 6 while($row = mysql_fetch_assoc($result)) { 7 echo $row['field1']; 8 }
你在pdo中可以这个样
<?php $stmt = $db->query('SELECT * FROM table'); while($row = $stmt->fetch(PDO::FETCH_ASSOC)) { echo $row['field1']; }
或者
<?php $result = mysql_query('SELECT * from table') or die(mysql_error()); $num_rows = mysql_num_rows($result); while($row = mysql_fetch_assoc($result)) { echo $row['field1']; }
提示:如果你使用了方法像query()。这个方法返回一个PDOStatement 对象,如果你想取出结果,请这样使用:
<?php foreach($db->query('SELECT * FROM table') as $row) { echo $row['field1']; }
PDO数据是通过->fetch() 方法获得的,这个方法是你的statement处理的。
在fetch之前。最好告诉PDO这个数据你打算怎么fetch。在下个章节我会解释。
Fetch Modes
PDO::FETCH_ASSOC 可以在fetch() 和 fetchAll()中使用。 这个告诉PDO返回关联数组,字段的名字作为key。这还有很多fench方法。
首先我说明怎么选择fench 模式。
$stmt->fetch(PDO::FETCH_ASSOC)
在这里我用的是fetch,你也可以用:
- PDOStatement::fetchAll() 返回了一个数组包含了所有选择的行
- PDOStatement::fetchColumn() 返回下一行的一列作为结果集
- PDOStatement::fetchObject() 返回下一行作为一个对象
- PDOStatement::setFetchMode() 设置fetch模式
下面讨论fetch模式
- PDO::FETCH_ASSOC 关联数组
- PDO::FETCH_BOTH 默认的。返回关联数组和索引数组。
还有更多选项,可以阅读文档。
获取行的数量
不是通过mysql_num_rows 而是通过rowCount(),比如说:
<?php $stmt = $db->query('SELECT * FROM table'); $row_count = $stmt->rowCount(); echo $row_count.' rows selected';
获取插入的id
<?php $result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')"); $insertId = $db->lastInsertId();
Insert and Update or Delete statements
在mysql_*中我们是这样做的
<?php $results = mysql_query("UPDATE table SET field='value'") or die(mysql_error()); echo mysql_affected_rows($result);
在PDO中,同样可以这样:
<?php $affected_rows = $db->exec("UPDATE table SET field='value'"); echo $affected_rows;
在上面的语句中,执行了一个sql语句并且返回受影响的行数。
上面的方法在你查询语句中没有变量时很好用。如果有变量,就应该使用 prepared statement or parameterized statement 。
Prepared Statements
Q:什么是 Prepared Statements,我为什么要用他?
A:Prepared Statement 是一条预编译的sql语句,可以被执行多次。
典型的使用Prepared Statement 工作流:
- Prepare: 语句(statement)模版被application创建,发送到数据库管理系统(DBMS)。某些值仍然违背置顶,通过参数、占位符进行绑定
INSERT INTO PRODUCT (name, price) VALUES (?, ?)
-
DBMS进行解析、编译,得到最优的语句,把结果(语句)储存起来,并不执行。
-
执行。过后,程序为参数提供或绑定值,DBMS执行语句(一般会返回一个结果)。程序或许会执行多次因为它有不同的值,想获得不同的结果。咱这个例子里,把Bread作为第一个参数,1.00作为第二个参数。
你可以通过引入占位符使用预编译语句。
Q:什么是命名占位符(named placeholders ),怎么使用呢?
A:命名占位符,用过一个冒号而不是? 这样就不用去操心问号的顺序问题了
$stmt->bindParam(':bla', $bla);
<?php $stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name"); $stmt->execute(array(':name' => $name, ':id' => $id)); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
另一个对于OOP(面向对象编程)很友好的就是,命名占位符可以直接插入到你的对象,再然后加入到你的数据库。假设属性与字段相同
class person { public $name; public $add; function __construct($a,$b) { $this->name = $a; $this->add = $b; } } $demo = new person('john','29 bla district'); $stmt = $db->prepare("INSERT INTO table (name, add) value (:name, :add)"); $stmt->execute((array)$demo);
Q:好了,什么是匿名占位符(unnamed placeholders),怎么使用?
A:看个例子。
<?php $stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)"); $stmt->bindValue(1, $name, PDO::PARAM_STR); $stmt->bindValue(2, $add, PDO::PARAM_STR); $stmt->execute(); $stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)"); $stmt->execute(array('john', '29 bla district'));
注意:在匿名占位符我们一定要注意在数组中的顺序,在PDOStatement::execute() 方法中。
SELECT, INSERT, UPDATE, DELETE prepared queries
- select
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name"); $stmt->execute(array(':name' => $name, ':id' => $id)); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
- insert
$stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)"); $stmt->execute(array(':field1' => $field1, ':field2' => $field2)); $affected_rows = $stmt->rowCount();
- delete
$stmt = $db->prepare("DELETE FROM table WHERE id=:id"); $stmt->bindValue(':id', $id, PDO::PARAM_STR); $stmt->execute(); $affected_rows = $stmt->rowCount();
- update
$stmt = $db->prepare("UPDATE table SET name=? WHERE id=?"); $stmt->execute(array($name, $id)); $affected_rows = $stmt->rowCount();
注意:
PDO和Mysqli也不是完全的安全。有机会会翻译一遍这个文章,这里就简单说一下:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $pdo->query('SET NAMES GBK'); $stmt = $pdo->prepare("SELECT * FROM test WHERE name = ? LIMIT 1"); $stmt->execute(array(chr(0xbf) . chr(0x27) . " OR 1=1 /*"));
下面是一个封装的类
1 class CPdo{ 2 protected $_dsn = "mysql:host=localhost;dbname=test"; 3 protected $_name = "root"; 4 protected $_pass = ""; 5 protected $_condition = array(); 6 protected $pdo; 7 protected $fetchAll; 8 protected $query; 9 protected $result; 10 protected $num; 11 protected $mode; 12 protected $prepare; 13 protected $row; 14 protected $fetchAction; 15 protected $beginTransaction; 16 protected $rollback; 17 protected $commit; 18 protected $char; 19 private static $get_mode; 20 private static $get_fetch_action; 21 /** 22 *pdo construct 23 */ 24 public function __construct($pconnect = false) { 25 $this->_condition = array(PDO::ATTR_PERSISTENT => $pconnect); 26 $this->pdo_connect(); 27 } 28 /** 29 *pdo connect 30 */ 31 private function pdo_connect() { 32 try{ 33 $this->pdo = new PDO($this->_dsn,$this->_name,$this->_pass,$this->_condition); 34 } 35 catch(Exception $e) { 36 return $this->setExceptionError($e->getMessage(), $e->getline, $e->getFile); 37 } 38 } 39 /** 40 *self sql get value action 41 */ 42 public function getValueBySelfCreateSql($sql, $fetchAction = "assoc",$mode = null) { 43 $this->fetchAction = $this->fetchAction($fetchAction); 44 $this->result = $this->setAttribute($sql, $this->fetchAction, $mode); 45 $this->AllValue = $this->result->fetchAll(); 46 return $this->AllValue; 47 } 48 /** 49 *select condition can query 50 */ 51 private function setAttribute($sql, $fetchAction, $mode) { 52 $this->mode = self::getMode($mode); 53 $this->fetchAction = self::fetchAction($fetchAction); 54 $this->pdo->setAttribute(PDO::ATTR_CASE, $this->mode); 55 $this->query = $this->base_query($sql); 56 $this->query->setFetchMode($this->fetchAction); 57 return $this->query; 58 } 59 /** 60 *get mode action 61 */ 62 private static function getMode($get_style){ 63 switch($get_style) { 64 case null: 65 self::$get_mode = PDO::CASE_NATURAL; 66 break; 67 case true: 68 self::$get_mode = PDO::CASE_UPPER; 69 break; 70 case false; 71 self::$get_mode= PDO::CASE_LOWER; 72 break; 73 } 74 return self::$get_mode; 75 } 76 /** 77 *fetch value action 78 */ 79 private static function fetchAction($fetchAction) { 80 switch($fetchAction) { 81 case "assoc": 82 self::$get_fetch_action = PDO::FETCH_ASSOC; //asso array 83 break; 84 case "num": 85 self::$get_fetch_action = PDO::FETCH_NUM; //num array 86 break; 87 case "object": 88 self::$get_fetch_action = PDO::FETCH_OBJ; //object array 89 break; 90 case "both": 91 self::$get_fetch_action = PDO::FETCH_BOTH; //assoc array and num array 92 break; 93 default: 94 self::$get_fetch_action = PDO::FETCH_ASSOC; 95 break; 96 } 97 return self::$get_fetch_action; 98 } 99 /** 100 *get total num action 101 */ 102 public function rowCount($sql) { 103 $this->result = $this->base_query($sql); 104 $this->num = $this->result->rowCount(); 105 return $this->num; 106 } 107 /* 108 *simple query and easy query action 109 */ 110 public function query($table, $column = "*",$condition = array(), $group = "",$order = "", $having = "", $startSet = "",$endSet = "",$fetchAction = "assoc",$params = null){ 111 $sql = "select ".$column." from `".$table."` "; 112 if ($condition != null) { 113 foreach($condition as $key=>$value) { 114 $where .= "$key = '$value' and "; 115 } 116 $sql .= "where $where"; 117 $sql .= "1 = 1 "; 118 } 119 if ($group != "") { 120 $sql .= "group by ".$group." "; 121 } 122 if ($order != "") { 123 $sql .= " order by ".$order." "; 124 } 125 if ($having != "") { 126 $sql .= "having '$having' "; 127 } 128 if ($startSet != "" && $endSet != "" && is_numeric($endSet) && is_numeric($startSet)) { 129 $sql .= "limit $startSet,$endSet"; 130 } 131 $this->result = $this->getValueBySelfCreateSql($sql, $fetchAction, $params); 132 return $this->result; 133 } 134 /** 135 *execute delete update insert and so on action 136 */ 137 public function exec($sql) { 138 $this->result = $this->pdo->exec($sql); 139 $substr = substr($sql, 0 ,6); 140 if ($this->result) { 141 return $this->successful($substr); 142 } else { 143 return $this->fail($substr); 144 } 145 } 146 /** 147 *prepare action 148 */ 149 public function prepare($sql) { 150 $this->prepare = $this->pdo->prepare($sql); 151 $this->setChars(); 152 $this->prepare->execute(); 153 while($this->rowz = $this->prepare->fetch()) { 154 return $this->row; 155 } 156 } 157 /** 158 *USE transaction 159 */ 160 public function transaction($sql) { 161 $this->begin(); 162 $this->result = $this->pdo->exec($sql); 163 if ($this->result) { 164 $this->commit(); 165 } else { 166 $this->rollback(); 167 } 168 } 169 /** 170 *start transaction 171 */ 172 private function begin() { 173 $this->beginTransaction = $this->pdo->beginTransaction(); 174 return $this->beginTransaction; 175 } 176 /** 177 *commit transaction 178 */ 179 private function commit() { 180 $this->commit = $this->pdo->commit(); 181 return $this->commit; 182 } 183 /** 184 *rollback transaction 185 */ 186 private function rollback() { 187 $this->rollback = $this->pdo->rollback(); 188 return $this->rollback; 189 } 190 /** 191 *base query 192 */ 193 private function base_query($sql) { 194 $this->setChars(); 195 $this->query = $this->pdo->query($sql); 196 return $this->query; 197 } 198 /** 199 *set chars 200 */ 201 private function setChars() { 202 $this->char = $this->pdo->query("SET NAMES 'UTF8'"); 203 return $this->char; 204 } 205 /** 206 *process sucessful action 207 */ 208 private function successful($params){ 209 return "The ".$params." action is successful"; 210 } 211 /** 212 *process fail action 213 */ 214 private function fail($params){ 215 return "The ".$params." action is fail"; 216 } 217 /***进程异常动作 218 *process exception action 219 */ 220 private function setExceptionError($getMessage, $getLine ,$getFile) { 221 echo "Error message is ".$getMessage."<br /> The Error in ".$getLine." line <br /> This file dir on ".$getFile; 222 exit(); 223 } 224 }
封装类2
1 <?php 2 /** 3 */ 4 5 //使用pdo连接数据库 封装增删改查 6 7 class DB{ 8 9 //定义私有属性 10 private $host; 11 private $port; 12 private $username; 13 private $password; 14 private $dbname; 15 private $charset; 16 private $dbtype; 17 private $pdo; 18 19 //定义构造函数自动加载配置文件 20 function __construct(){ 21 //加载配置文件 22 include_once('./config/config.php'); 23 24 //给属性赋值 25 $this->dbtype = $config['db']; 26 $this->host = $config['host']; 27 $this->username = $config['username']; 28 $this->password = $config['password']; 29 $this->charset = $config['charset']; 30 $this->port = $config['port']; 31 $this->dbname = $config['dbname']; 32 33 //pdo连接数据库 34 $this->pdo = new PDO("$this->dbtype:host=$this->host;dbname=$this->dbname","$this->username","$this->password"); 35 //发送编码 36 $this->pdo->query("set names $this->charset"); 37 } 38 39 /** 40 * 定义执行查询sql语句的方法 41 * 参数: 查询sql语句 42 * 返回: 二维关联数组 43 */ 44 public function query($sql){ 45 $res = $this->pdo->query($sql); 46 $res->setFetchMode(PDO::FETCH_ASSOC); 47 $arr = $res->fetchAll(); 48 return $arr; 49 } 50 51 52 /** 53 * 查询一行记录的方法 54 * 参数:表名 条件(不包含where) 55 * 返回:一维关联数组 56 */ 57 public function getRow($tablename,$where){ 58 //组装sql语句 59 $sql = "select * from $tablename where $where"; 60 //查询 61 $res = $this->pdo->query($sql); 62 $res->setFetchMode(PDO::FETCH_ASSOC); 63 $arr = $res->fetch(); 64 return $arr; 65 } 66 67 68 /** 69 * 查询全部记录 70 * 参数:表名 71 * 返回:二维关联数组 72 */ 73 public function getAll($tablename){ 74 $res = $this->pdo->query("select * from $tablename"); 75 $res->setFetchMode(PDO::FETCH_ASSOC); 76 $arr = $res->fetchAll(); 77 return $arr; 78 } 79 80 /** 81 * 查询某个字段 82 * 参数: 字段名(多个的话用逗号隔开) 表名 条件(不含where) 83 * 返回: 二维关联数组 84 */ 85 public function getOne($column,$tablename,$where="1"){ 86 //拼接sql语句 87 $sql = "select $column from $tablename where $where"; 88 $rs = $this->pdo->query($sql); 89 $rs->setFetchMode(PDO::FETCH_ASSOC); 90 //$col = $rs->fetchColumn(); 91 $col = $rs->fetchAll(); 92 return $col; 93 } 94 95 96 /** 97 * 查询最后一次插入的数据 98 * 参数:表名 99 * 返回:数组 100 */ 101 public function getlastone($tablename){ 102 $sql = "select * from $tablename where id=(select max(id) from $tablename)"; 103 $res = $this->pdo->query($sql); 104 $res->setFetchMode(PDO::FETCH_ASSOC); 105 $arr = $res->fetch(); 106 return $arr; 107 } 108 109 110 /** 111 * 向数据库中添加一条信息 112 * 参数:表名 一维关联数组 113 * 返回: 布尔值 114 */ 115 public function insert($tablename,$arr){ 116 //拿到数组之后先处理数组 过滤字段 117 //取出表中的字段 118 $sql = "select COLUMN_NAME from information_schema.COLUMNS where table_name = '$tablename' and table_schema ='$this->dbname'"; 119 $columns = $this->pdo->query($sql); 120 $columns->setFetchMode(PDO::FETCH_ASSOC); 121 $columns = $columns->fetchAll(); 122 $cols = array(); //存储表中的全部字段 123 foreach($columns as $key=>$val){ 124 $cols[] = $val['COLUMN_NAME']; 125 } 126 //将要入库的数组进行键值分离 127 $keys = array(); 128 $values = ''; 129 foreach($arr as $k=>$v){ 130 if(!in_array($k,$cols)){ 131 unset($arr[$k]); 132 }else{ 133 $keys[] = $k; 134 $values .= "'".$v."',"; 135 } 136 } 137 $column = implode(',',$keys); 138 $values = substr($values,0,-1); 139 //拼接sql语句 140 $sql = "insert into $tablename($column) values ($values)"; 141 $res = $this->pdo->exec($sql); 142 return $res; 143 } 144 145 146 /** 147 * 删除数据 其实就是改变字段值使之不被查询 148 * 参数:表名 条件(不含where) 149 * 返回:布尔 150 */ 151 public function delete($tablename,$where){ 152 $sql = "update $tablename set is_del=1 where $where"; 153 $res = $this->pdo->exec($sql); 154 return $res; 155 } 156 157 158 /** 159 * 修改数据 160 * 参数:表名 要修改的数据的数组 161 * 返回:布尔 162 */ 163 public function update($tablename,$arr,$where){ 164 //处理传过来的数组 165 $str = ""; 166 foreach($arras $k=>$v){ 167 $str .= "$k='".$v."',"; 168 } 169 //截取字符串 170 $str = substr($str,0,-1); 171 //拼接sql语句 172 $sql = "update $tablename set $str where $where"; 173 $res = $this->pdo->exec($sql); 174 return $res; 175 } 176 }