2009-10-30 31 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

相关问题