php memcached mysql_PHP Memcached使用详解
翻譯爛到家了,看不順眼輕噴。。。 1.為什么要使用PDO? mysql_函數已經過時,相當一段時間以來,mysql_函數在其他SQL數據庫編程接口方面已經有所差別;它不支持預處理,存儲過程,事務等一些現代數據庫設計思想,SQL語句字符串轉義函數 mysql_real_escape_s
翻譯爛到家了,看不順眼輕噴。。。
1.為什么要使用PDO?
mysql_*函數已經過時,相當一段時間以來,mysql_*函數在其他SQL數據庫編程接口方面已經有所差別;它不支持預處理,存儲過程,事務等一些現代數據庫設計思想,SQL語句字符串轉義函數 mysql_real_escape_string() 和 拼接SQL語句的編程方法 已經過時并且很容易出錯。最近一段時間里,它缺乏開發者的關注,缺少維護將可能導致一些安全問題不能被即時修復,或者在適配新版本的MySQL的時候不能正常工作,這成為mysql_*函數面臨的的另一個問題。PHP社區最近也對mysql_*函數給出不建議使用的建議,也有可能在未來的版本中最終被棄用(不過不用過于擔心,這可能還需要很長一段時間)。
PDO擁有更好的編程接口,你可以使用它寫出更加簡潔,高效,安全的代碼。PDO還為不同的SQL數據庫提供了不同的驅動,方便你使用新的數據庫而不用再學習不同的編程接口。與拼接SQL語句構造查詢語句不同,綁定參數可以簡潔方便的構造出更加安全的查詢語句,使用綁定參數的方法在 多次相似語句查詢(僅僅某個參數不同)中也可以提高不少性能。PDO在錯誤處理方面也提供了多種方法。mysql_*函數缺乏一致的處理,與PDO的異常模式相比,或者說沒有處理異常,使用PDO,你可以得到一致的錯誤處理,這將節省您大量的時間來跟蹤問題。
在當前的PHP版本中,PDO模塊是默認安裝啟用的,但是在使用PDO前你還需要安裝另外兩個軟件包,一個是pdo_mysql數據庫驅動程序,另外一個是類似php-mysql的mysql驅動程序。
2.連接MySQL
以前的方式:
$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
mysql_set_charset('UTF-8', $link);
新的方式:
* 創建一個PDO對象,參數包括 DSN, username, password 和 一個驅動選項的數組(可忽略)。
* DSN其實就是一個告訴PDO該使用哪一種數據庫驅動 和 一些連接信息的字符串,了解更多 PDO MYSQL DSN .
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');
注意:確保DSN中設置了字符編碼信息,否則將可能返回字符編碼設置錯誤的信息,出于安全考慮,DSN最好包括字符編碼信息設置。
你也可以在第四個參數數組里填寫一些驅動選項,建議將 PDO異常模式(下文講解) 和 關閉預處理模擬(默認打開的,僅對于舊版本MySQL有用)兩個參數加入到第四個參數數組中。
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password', array(PDO::ATTR_EMULATE_PREPARES => false,PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
你也可以在創建PDO對象后再通過setAttribute方法設置相應選項。
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
3.錯誤處理
mysql_*函數的錯誤處理
//connected to mysql
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));
OR die()是個不錯的錯誤處理方法,但是會因此結束頁面,將錯誤信息呈現到用戶面前,這可能是我們不想看到的結果。
PDO有三種錯誤處理模式:
PDO::ERRMODE_SILENT # 和 mysql_*函數類似,檢查代碼并查看 $db->errorInfo(); 獲取詳細信息。
PDO::ERRMODE_WARNING # 拋出PHP警告。
PDO::ERRMODE_EXCEPTION #拋出 PDOException 異常,在我認為,這是我們應該使用的模式, 這和 die(mysql_error()); 類似,但是它可以捕獲并拋出具體異常信息。
code:
try {
//connect as appropriate as above
$db->query('hi'); //invalid query!
} catch(PDOException $ex) {
echo "An Error occured!"; //user friendly message
some_logging_function($ex->getMessage());
}
注意:你可以不用立即執行并捕獲異常,你可以在任何合適的時候隨時捕獲。
function getData($db) {
$stmt = $db->query("SELECT * FROM table");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
//then much later
try {
getData($db);
} catch(PDOException $ex) {
//handle me.
}
如果你不想使用try/catch來處理異常,就像使用OR die()那樣處理,在production模式下關閉display_errors選項即可。
4.簡單的查詢語句(SELECT)
mysql_*代碼:
$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'].' '.$row['field2']; //etc...
}
PDO代碼:
foreach($db->query('SELECT * FROM table') as $row) {
echo $row['field1'].' '.$row['field2']; //etc...
}
query() 方法返回了一個 PDOStatement 對象,你可以通過如下方法獲取結果:
$stmt = $db->query('SELECT * FROM table');
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['field1'].' '.$row['field2']; //etc...
}
或者
$stmt = $db->query('SELECT * FROM table');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
//use $results
# Fetch Modes
注意 fetch() 和 fetchAll() 代碼中的PDO::FETCH_ASSOC ,它高速 PDO 以關聯數組的形式返回 鍵,值;其他比如PDO::FETCH_NUM模式,則返回數值鍵值的數組,默認模式是 PDO::FETCH_BOTH 則返回前面兩者的集合,既有數值鍵值的數組,又有關聯數組。PDO也可以獲取數據返回對象PDO::FETCH_OBJ,PDO::FETCH_CLASS,PDO::FETCH_BOUND,bindColumn方法等更多內容,請閱讀: PDOStatement Fetch documentation。
# 獲取數據行數(Getting Row Count)
代替 mysql_num_rows 方法,你可以使用 PDOStatement對象的rowCount();方法。
$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';
注意:官方文檔稱此函數僅適用于返回 `UPDATE`, `INSERT`, `DELETE`操作的`affected rows`,而 `SELECT`操作,僅對于`PDO_MYSQL` 驅動,此函數同樣適用(謹記),在操作其他數據庫的時候尤其注意。
# 獲取最后操作ID(Getting the Last Insert Id)
mysql_*代碼:
$result = mysql_query("INSERT INTO table(firstname, lastname) VALUES('John', 'Doe')") or die("Insert Failed ".mysql_error());
$insert_id = mysql_insert_id();
PDO代碼:
$result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')");
$insertId = $db->lastInsertId();
5.執行 INSERT, UPDATE, DELETE 操作
mysql_*代碼:
$results = mysql_query("UPDATE table SET field='value'") or die(mysql_error());
$affected_rows = mysql_affected_rows($result);
echo $affected_rows.' were affected';
PDO代碼:
$affected_rows = $db->exec("UPDATE table SET field='value'");
echo $affected_rows.' were affected'
DELETE , INSERT 操作同樣適用。
6.運行帶有查詢參數的語句(Running Statements With Parameters)
對于 不攜帶任何參數的查詢語句,我們可以使用 query方法處理SELECT操作,使用exec方法處理 INSERT,UPDATE,INSERT操作,而對于攜帶查詢參數的語句,你應該使用綁定參數的方法來安全的處理這些操作。
mysql_*代碼:
$results = mysql_query(sprintf("SELECT * FROM table WHERE id='%s' AND name='%s'",
mysql_real_escape_string($id), mysql_real_escape_string($name))) or die(mysql_error());
$rows = array();
while($row = mysql_fetch_assoc($results)){
$rows[] = $row;
}
PDO代碼:
$stmt = $db->prepare("SELECT * FROM table WHERE id=? AND name=?");
$stmt->execute(array($id, $name));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
prepare方法將查詢語句發送到服務器,以“?”作為參數占位符進行編譯,execute方法將查詢參數發送到服務器,運行之前編譯好的查詢語句。因為 查詢語句 和 查詢參數 是分開發送的,所以在參數里的SQL語句是不可能被執行的,所以不會發生 SQL注入,這是一種比連接字符串構造SQL語句更加安全的解決方法。
注意:當你使用**綁定參數**的時候,不要對"?"占位符使用引號(SQL語句原來是對參數使用引號的),因為參數類型是在execute方法的時候確定的,所以在prepare的時候不必對占位符使用引號。
還有一些綁定參數的方法,bindValue方法可以分別綁定每個參數來代替execute方法的數組方式,同時還分別設置每個參數的類型。
$stmt = $db->prepare("SELECT * FROM table WHERE id=? AND name=?");
$stmt->bindValue(1, $id, PDO::PARAM_INT);
$stmt->bindValue(2, $name, PDO::PARAM_STR);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
#命名占位符
如果你有許多參數需要綁定,不要使用問號占位符,以防混淆出錯,你可以使用命名占位符代替問號占位符。
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->bindValue(':name', $name, PDO::PARAM_STR);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
你也可以使用execute方法,以數組的方式綁定參數:
$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, DELETE, UPDATE 預處理查詢
INSERT, DELETE, UPDATE 預處理語句的使用和SELECT類似,我們舉幾個例子:
$stmt = $db->prepare("INSERT INTO table(field1,field2,field3,field4,field5) VALUES(:field1,:field2,:field3,:field4,:field5)");
$stmt->execute(array(':field1' => $field1, ':field2' => $field2, ':field3' => $field3, ':field4' => $field4, ':field5' => $field5));
$affected_rows = $stmt->rowCount();
$stmt = $db->prepare("DELETE FROM table WHERE id=:id");
$stmt->bindValue(':id', $id, PDO::PARAM_STR);
$stmt->execute();
$affected_rows = $stmt->rowCount();
$stmt = $db->prepare("UPDATE table SET name=? WHERE id=?");
$stmt->execute(array($name, $id));
$affected_rows = $stmt->rowCount();
#在預處理中使用SQL函數
無效方法:
//THIS WILL NOT WORK!
$time = 'NOW()';
$name = 'BOB';
$stmt = $db->prepare("INSERT INTO table(`time`, `name`) VALUES(?, ?)");
$stmt->execute(array($time, $name));
正確方法
$name = 'BOB';
$stmt = $db->prepare("INSERT INTO table(`time`, `name`) VALUES(NOW(), ?)");
$stmt->execute(array($name));
你也可以在SQL函數里綁定參數:
$name = 'BOB';
$password = 'badpass';
$stmt = $db->prepare("INSERT INTO table(`hexvalue`, `password`) VALUES(HEX(?), PASSWORD(?))");
$stmt->execute(array($name, $password));
但是不能作為LIKE的參數:
//THIS DOES NOT WORK
$stmt = $db->prepare("SELECT field FROM table WHERE field LIKE %?%");
$stmt->bindParam(1, $search, PDO::PARAM_STR);
$stmt->execute();
正確使用LIKE并綁定參數的方法:
$stmt = $db->prepare("SELECT field FROM table WHERE field LIKE ?");
$stmt->bindValue(1, "%$search%", PDO::PARAM_STR);
$stmt->execute();
注意:這里使用的是bindValue而不是bindParam,否則會發生PDOException或致命錯誤。
#使用循環運行預處理語句
預處理語句可以一次設置,多次調用,因為僅在第一次傳入的時候編譯,因此在后來的多次調用中提高了不少效率。
典型的應用就是bindParam,bindParam與bindValue的不同之處在于,它不是綁定了參數的值,而是綁定參數變量本身,因此,如果參數變量變化了,那么在execute處理的時候,查詢也將相應變化。
$values = array('bob', 'alice', 'lisa', 'john');
$name = '';
$stmt = $db->prepare("INSERT INTO table(`name`) VALUES(:name)");
$stmt->bindParam(':name', $name, PDO::PARAM_STR);
foreach($values as $name) {
$stmt->execute();
}
6.PDO中的事務(Transactions)
注意:調用beginTransaction()方法即自動關閉了自動提交。
try {
$db->beginTransaction();
$db->exec("SOME QUERY");
$stmt = $db->prepare("SOME OTHER QUERY?");
$stmt->execute(array($value));
$stmt = $db->prepare("YET ANOTHER QUERY??");
$stmt->execute(array($value2, $value3));
$db->commit();
} catch(PDOException $ex) {
//Something went wrong rollback!
$db->rollBack();
echo $ex->getMessage();
}
原文鏈接:PDO Tutorial for MySQL Developers
參考鏈接:PDO Documentation
延伸閱讀:Validation and SQL Injection
總結
以上是生活随笔為你收集整理的php memcached mysql_PHP Memcached使用详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 重新安装mysql5.7.21_linu
- 下一篇: javascript number转st