2009-10-30 41 views
53

在O'Reilly出版閱讀「高性能MySQL的」,我在下面的是否使用「組名稱」

另一種常見的垃圾查詢跌跌撞撞的SET NAMES UTF8,這是錯誤的方式(不改變 客戶端庫的字符集; 隻影響服務器)。

我有點困惑,因爲我曾經在每個腳本的頂部放置了「SET NAMES utf8」,讓db知道我的查詢是utf8編碼的。

任何人都可以評論上述報價,或者更正式地說,您的建議/最佳實踐是什麼,以確保我的數據庫工作流程能夠識別unicode。

我的目標語言是php和python,如果這是相關的。

+2

你最終實現了什麼技術? –

回答

28

mysql_set_charset()創建將是一種選擇的連接 - 但一個選項僅限於ext/mysql。對於ext/mysqli它是mysqli_set_charsetPDO::mysql您需要指定連接參數。

由於使用此函數會導致MySQL API調用,因此應該認爲它比發出查詢要快得多。

在性能方面,確保腳本和MySQL服務器之間基於UTF-8通信的最快方法是正確設置MySQL服務器。由於SET NAMES xequivalent

SET character_set_client = x; 
SET character_set_results = x; 
SET character_set_connection = x; 

SET character_set_connection = x內部還執行SET collation_connection = <<default_collation_of_character_set_x>>你也可以在你的my.ini/cnf設置these server variables靜態。

請注意其他應用程序在同一個MySQL服務器實例上運行並需要其他字符集時可能出現的問題。

+3

作爲PHP 5.0.5的,存在的mysqli的方法:http://php.net/mysqli_set_charset – xofer

+0

我提到'mysql_set_charset()' - 這是包括在舊'EXT/mysql'的功能。如上所述,「PDO」和「ext/mysqli」都不直接爲此操作提供任何支持。 –

+1

似乎我發佈的鏈接不可靠。這裏有一個更好的:http://php.net/manual/en/mysqli.set-charset.php不知道你是如何意味着mysqli不支持這個操作。 – xofer

9

不確定py,但php現在有mysql_set_charset,這表示這是「不推薦使用mysql_query()更改charset [和]來執行SET NAMES的首選方法。」請注意,該功能是爲MySQL 5.0.7引入的,因此它不適用於早期版本。

mysql_set_charset('utf8', $link); 

其中$鏈接是mysql_connect

21

TLDR

// The key is the "charset=utf8" part. 
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8'; 
$dbh = new PDO($dsn, 'user', 'pass'); 

這個答案對PHP的PDO庫的重視,因爲它是如此的普遍。

簡要提醒 - mysql是一個客戶端 - 服務器體系結構。這很重要,因爲不僅有mysql服務器在那裏有實際的數據庫,而且還有單獨的mysql客戶端驅動程序,這是與mysql服務器交談的東西(它們是獨立的實體)。你可以有點說,MySQL客戶端和pdo混合在一起。

當你使用set names utf8時,你發出一個標準的sql查詢到mysql。儘管sql查詢確實通過了pdo,然後通過了mysql客戶端庫,然後最終到達了mysql服務器,但是隻有mysql服務器解析並解釋了該sql查詢。這很重要,因爲mysql服務器不會向pdo發送任何消息,或者mysql客戶端讓它知道字符集和編碼已更改,所以pdo完全不瞭解它發生的事實。

它沒有這樣做,因爲客戶端庫不能正確處理字符串,如果它是不知道目前的字符集是非常重要的。如果客戶端不知道正確的字符集,大多數常見操作都可以正常工作,但不會出現字符串轉義的情況,如PDO::quote。你可能會認爲你不需要擔心這樣的手工原始字符串轉義,因爲你使用準備好的語句,但事實是,絕大多數的PDO:MySQL用戶在不知不覺中使用emulated prepared statements,因爲它已經爲PDO的默認設置:MySQL的驅動程序現在很長一段時間。模擬的預準備語句不使用由mysql api提供的真實本地mysql準備語句;相反,php的所有值相當於調用PDO::quote(),並且str_replacing你的佔位符的引用值。

因爲你不能正確轉義的字符串,除非你知道你正在使用的字符集,如果你已經通過集名稱更改爲某些字符集,這些模擬預處理語句很容易受到SQL注入。無論sql注入的可能性如何,如果您使用用於不同字符集的轉義方案,仍然可能會破壞字符串。

對於PDO MySQL驅動程序,當您連接,通過specifying it in the DSN可以指定字符集。如果你這樣做,客戶端庫和服務器都會知道字符集。

// The key is the "charset=utf8" part. 
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8'; 
$dbh = new PDO($dsn, 'user', 'pass'); 

但是不當的字符串轉義是不是唯一的問題。例如,您也可能在使用PDO::bindColumn時遇到問題,因爲列名被指定爲字符串,所以編碼也很重要。例如列名爲ütube(注意變音符號),並且您通過設置名稱從latin切換到utf8,然後嘗試使用$stmt->bindColumn('ütube', $var);ütube是utf8編碼的字符串,因爲您的php文件是utf8編碼的。它不會工作,你需要將字符串編碼爲latin1變體......現在你有各種瘋狂的事情發生。

+2

現在(2014年9月)PDO是將PHP與數據庫連接起來的最新且最穩健的方式,我認爲這個答案應該被接受。 – rogeriopradoj

相關問題