php memcached mysql_PHP Memcached使用详解
翻譯爛到家了,看不順眼輕噴。。。 1.為什么要使用PDO? mysql_函數(shù)已經(jīng)過(guò)時(shí),相當(dāng)一段時(shí)間以來(lái),mysql_函數(shù)在其他SQL數(shù)據(jù)庫(kù)編程接口方面已經(jīng)有所差別;它不支持預(yù)處理,存儲(chǔ)過(guò)程,事務(wù)等一些現(xiàn)代數(shù)據(jù)庫(kù)設(shè)計(jì)思想,SQL語(yǔ)句字符串轉(zhuǎn)義函數(shù) mysql_real_escape_s
翻譯爛到家了,看不順眼輕噴。。。
1.為什么要使用PDO?
mysql_*函數(shù)已經(jīng)過(guò)時(shí),相當(dāng)一段時(shí)間以來(lái),mysql_*函數(shù)在其他SQL數(shù)據(jù)庫(kù)編程接口方面已經(jīng)有所差別;它不支持預(yù)處理,存儲(chǔ)過(guò)程,事務(wù)等一些現(xiàn)代數(shù)據(jù)庫(kù)設(shè)計(jì)思想,SQL語(yǔ)句字符串轉(zhuǎn)義函數(shù) mysql_real_escape_string() 和 拼接SQL語(yǔ)句的編程方法 已經(jīng)過(guò)時(shí)并且很容易出錯(cuò)。最近一段時(shí)間里,它缺乏開(kāi)發(fā)者的關(guān)注,缺少維護(hù)將可能導(dǎo)致一些安全問(wèn)題不能被即時(shí)修復(fù),或者在適配新版本的MySQL的時(shí)候不能正常工作,這成為mysql_*函數(shù)面臨的的另一個(gè)問(wèn)題。PHP社區(qū)最近也對(duì)mysql_*函數(shù)給出不建議使用的建議,也有可能在未來(lái)的版本中最終被棄用(不過(guò)不用過(guò)于擔(dān)心,這可能還需要很長(zhǎng)一段時(shí)間)。
PDO擁有更好的編程接口,你可以使用它寫(xiě)出更加簡(jiǎn)潔,高效,安全的代碼。PDO還為不同的SQL數(shù)據(jù)庫(kù)提供了不同的驅(qū)動(dòng),方便你使用新的數(shù)據(jù)庫(kù)而不用再學(xué)習(xí)不同的編程接口。與拼接SQL語(yǔ)句構(gòu)造查詢語(yǔ)句不同,綁定參數(shù)可以簡(jiǎn)潔方便的構(gòu)造出更加安全的查詢語(yǔ)句,使用綁定參數(shù)的方法在 多次相似語(yǔ)句查詢(僅僅某個(gè)參數(shù)不同)中也可以提高不少性能。PDO在錯(cuò)誤處理方面也提供了多種方法。mysql_*函數(shù)缺乏一致的處理,與PDO的異常模式相比,或者說(shuō)沒(méi)有處理異常,使用PDO,你可以得到一致的錯(cuò)誤處理,這將節(jié)省您大量的時(shí)間來(lái)跟蹤問(wèn)題。
在當(dāng)前的PHP版本中,PDO模塊是默認(rèn)安裝啟用的,但是在使用PDO前你還需要安裝另外兩個(gè)軟件包,一個(gè)是pdo_mysql數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序,另外一個(gè)是類似php-mysql的mysql驅(qū)動(dòng)程序。
2.連接MySQL
以前的方式:
$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
mysql_set_charset('UTF-8', $link);
新的方式:
* 創(chuàng)建一個(gè)PDO對(duì)象,參數(shù)包括 DSN, username, password 和 一個(gè)驅(qū)動(dòng)選項(xiàng)的數(shù)組(可忽略)。
* DSN其實(shí)就是一個(gè)告訴PDO該使用哪一種數(shù)據(jù)庫(kù)驅(qū)動(dòng) 和 一些連接信息的字符串,了解更多 PDO MYSQL DSN .
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');
注意:確保DSN中設(shè)置了字符編碼信息,否則將可能返回字符編碼設(shè)置錯(cuò)誤的信息,出于安全考慮,DSN最好包括字符編碼信息設(shè)置。
你也可以在第四個(gè)參數(shù)數(shù)組里填寫(xiě)一些驅(qū)動(dòng)選項(xiàng),建議將 PDO異常模式(下文講解) 和 關(guān)閉預(yù)處理模擬(默認(rèn)打開(kāi)的,僅對(duì)于舊版本MySQL有用)兩個(gè)參數(shù)加入到第四個(gè)參數(shù)數(shù)組中。
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password', array(PDO::ATTR_EMULATE_PREPARES => false,PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
你也可以在創(chuàng)建PDO對(duì)象后再通過(guò)setAttribute方法設(shè)置相應(yīng)選項(xiàng)。
$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.錯(cuò)誤處理
mysql_*函數(shù)的錯(cuò)誤處理
//connected to mysql
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));
OR die()是個(gè)不錯(cuò)的錯(cuò)誤處理方法,但是會(huì)因此結(jié)束頁(yè)面,將錯(cuò)誤信息呈現(xiàn)到用戶面前,這可能是我們不想看到的結(jié)果。
PDO有三種錯(cuò)誤處理模式:
PDO::ERRMODE_SILENT # 和 mysql_*函數(shù)類似,檢查代碼并查看 $db->errorInfo(); 獲取詳細(xì)信息。
PDO::ERRMODE_WARNING # 拋出PHP警告。
PDO::ERRMODE_EXCEPTION #拋出 PDOException 異常,在我認(rèn)為,這是我們應(yīng)該使用的模式, 這和 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());
}
注意:你可以不用立即執(zhí)行并捕獲異常,你可以在任何合適的時(shí)候隨時(shí)捕獲。
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來(lái)處理異常,就像使用OR die()那樣處理,在production模式下關(guān)閉display_errors選項(xiàng)即可。
4.簡(jiǎn)單的查詢語(yǔ)句(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() 方法返回了一個(gè) PDOStatement 對(duì)象,你可以通過(guò)如下方法獲取結(jié)果:
$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 以關(guān)聯(lián)數(shù)組的形式返回 鍵,值;其他比如PDO::FETCH_NUM模式,則返回?cái)?shù)值鍵值的數(shù)組,默認(rèn)模式是 PDO::FETCH_BOTH 則返回前面兩者的集合,既有數(shù)值鍵值的數(shù)組,又有關(guān)聯(lián)數(shù)組。PDO也可以獲取數(shù)據(jù)返回對(duì)象PDO::FETCH_OBJ,PDO::FETCH_CLASS,PDO::FETCH_BOUND,bindColumn方法等更多內(nèi)容,請(qǐng)閱讀: PDOStatement Fetch documentation。
# 獲取數(shù)據(jù)行數(shù)(Getting Row Count)
代替 mysql_num_rows 方法,你可以使用 PDOStatement對(duì)象的rowCount();方法。
$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';
注意:官方文檔稱此函數(shù)僅適用于返回 `UPDATE`, `INSERT`, `DELETE`操作的`affected rows`,而 `SELECT`操作,僅對(duì)于`PDO_MYSQL` 驅(qū)動(dòng),此函數(shù)同樣適用(謹(jǐn)記),在操作其他數(shù)據(jù)庫(kù)的時(shí)候尤其注意。
# 獲取最后操作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.執(zhí)行 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.運(yùn)行帶有查詢參數(shù)的語(yǔ)句(Running Statements With Parameters)
對(duì)于 不攜帶任何參數(shù)的查詢語(yǔ)句,我們可以使用 query方法處理SELECT操作,使用exec方法處理 INSERT,UPDATE,INSERT操作,而對(duì)于攜帶查詢參數(shù)的語(yǔ)句,你應(yīng)該使用綁定參數(shù)的方法來(lái)安全的處理這些操作。
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方法將查詢語(yǔ)句發(fā)送到服務(wù)器,以“?”作為參數(shù)占位符進(jìn)行編譯,execute方法將查詢參數(shù)發(fā)送到服務(wù)器,運(yùn)行之前編譯好的查詢語(yǔ)句。因?yàn)?查詢語(yǔ)句 和 查詢參數(shù) 是分開(kāi)發(fā)送的,所以在參數(shù)里的SQL語(yǔ)句是不可能被執(zhí)行的,所以不會(huì)發(fā)生 SQL注入,這是一種比連接字符串構(gòu)造SQL語(yǔ)句更加安全的解決方法。
注意:當(dāng)你使用**綁定參數(shù)**的時(shí)候,不要對(duì)"?"占位符使用引號(hào)(SQL語(yǔ)句原來(lái)是對(duì)參數(shù)使用引號(hào)的),因?yàn)閰?shù)類型是在execute方法的時(shí)候確定的,所以在prepare的時(shí)候不必對(duì)占位符使用引號(hào)。
還有一些綁定參數(shù)的方法,bindValue方法可以分別綁定每個(gè)參數(shù)來(lái)代替execute方法的數(shù)組方式,同時(shí)還分別設(shè)置每個(gè)參數(shù)的類型。
$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);
#命名占位符
如果你有許多參數(shù)需要綁定,不要使用問(wèn)號(hào)占位符,以防混淆出錯(cuò),你可以使用命名占位符代替問(wèn)號(hào)占位符。
$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方法,以數(shù)組的方式綁定參數(shù):
$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 預(yù)處理查詢
INSERT, DELETE, UPDATE 預(yù)處理語(yǔ)句的使用和SELECT類似,我們舉幾個(gè)例子:
$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();
#在預(yù)處理中使用SQL函數(shù)
無(wú)效方法:
//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函數(shù)里綁定參數(shù):
$name = 'BOB';
$password = 'badpass';
$stmt = $db->prepare("INSERT INTO table(`hexvalue`, `password`) VALUES(HEX(?), PASSWORD(?))");
$stmt->execute(array($name, $password));
但是不能作為L(zhǎng)IKE的參數(shù):
//THIS DOES NOT WORK
$stmt = $db->prepare("SELECT field FROM table WHERE field LIKE %?%");
$stmt->bindParam(1, $search, PDO::PARAM_STR);
$stmt->execute();
正確使用LIKE并綁定參數(shù)的方法:
$stmt = $db->prepare("SELECT field FROM table WHERE field LIKE ?");
$stmt->bindValue(1, "%$search%", PDO::PARAM_STR);
$stmt->execute();
注意:這里使用的是bindValue而不是bindParam,否則會(huì)發(fā)生PDOException或致命錯(cuò)誤。
#使用循環(huán)運(yùn)行預(yù)處理語(yǔ)句
預(yù)處理語(yǔ)句可以一次設(shè)置,多次調(diào)用,因?yàn)閮H在第一次傳入的時(shí)候編譯,因此在后來(lái)的多次調(diào)用中提高了不少效率。
典型的應(yīng)用就是bindParam,bindParam與bindValue的不同之處在于,它不是綁定了參數(shù)的值,而是綁定參數(shù)變量本身,因此,如果參數(shù)變量變化了,那么在execute處理的時(shí)候,查詢也將相應(yīng)變化。
$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中的事務(wù)(Transactions)
注意:調(diào)用beginTransaction()方法即自動(dòng)關(guān)閉了自動(dòng)提交。
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
總結(jié)
以上是生活随笔為你收集整理的php memcached mysql_PHP Memcached使用详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 重新安装mysql5.7.21_linu
- 下一篇: chart绑定mysql数据源_MSCh