是否使用“设置名称”断续器

2022-08-30 09:21:48

在阅读O'Reilly的“高性能MySQL”时,我偶然发现了以下内容

另一个常见的垃圾查询是 SET NAMES UTF8,这无论如何都是错误的做事方式(它不会更改客户端库的字符集;它只影响服务器)。

我有点困惑,因为我曾经在每个脚本的顶部放置“SET NAMES utf8”,让db知道我的查询是utf8编码的。

任何人都可以评论上面的引用,或者更正式地说,你的建议/最佳实践是什么,以确保我的数据库工作流程是unicode感知的。

我的目标语言是php和python,如果这是相关的。


答案 1

mysql_set_charset() 将是一个选项 - 但仅限于 ext/mysql 的选项。对于 ext/mysqli,它是mysqli_set_charset对于 PDO,您需要指定一个连接参数。::mysql

由于使用此函数会导致MySQL API调用,因此应该认为它比发出查询快得多。

在性能方面,确保脚本和MySQL服务器之间基于UTF-8的通信的最快方法是正确设置MySQL服务器。AS 等效于SET NAMES x

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

而内部也执行,您也可以在 中静态设置这些服务器变量SET character_set_connection = xSET collation_connection = <<default_collation_of_character_set_x>>my.ini/cnf

请注意在同一MySQL服务器实例上运行的其他应用程序可能出现的问题,并且需要一些其他字符集。


答案 2

断续器

// 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混合在一起。

使用 时,可以向 mysql 发出标准 sql 查询。虽然sql查询确实通过pdo,然后通过mysql客户端库,然后最终到达mysql服务器,但只有mysql服务器解析并解释该sql查询。这很重要,因为mysql服务器不会将任何消息发送回pdo或mysql客户端,让它知道字符集和编码已更改,因此mysql客户端和pdo都完全不知道它发生了。set names utf8

请务必不要这样做,因为如果客户端库不知道当前字符集,则无法正确处理字符串。大多数常见操作在客户端不知道正确字符集的情况下可以正常工作,但字符串转义(如 PDO::quote)则无法正常工作。您可能认为您不必担心这种手动原始字符串转义,因为您使用了预准备语句,但事实是绝大多数pdo:mysql用户在不知不觉中使用模拟的预准备语句,因为它已经是pdo:mysql驱动程序的默认设置很长一段时间了。模拟的预准备语句不使用 mysql api 提供的真正本机 mysql 预准备语句;相反,php相当于调用所有值,并str_replacing所有占位符,并为您引用值。PDO::quote()

由于除非您知道正在使用的字符集,否则无法正确转义字符串,因此,如果您通过 更改为某些字符集,则这些模拟的预准备语句容易受到 sql 注入的影响。无论 sql 注入的可能性如何,如果使用用于不同字符集的转义方案,您仍然可以中断字符串。set names

对于 pdo mysql 驱动程序,可以在连接时通过在 DSN 中指定字符集来指定字符集。如果您这样做,客户端库和服务器都将知道字符集,因此事情将按预期方式工作。

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

但是,不正确的字符串转义并不是唯一的问题。例如,使用 PDO::bindColumn 也可能遇到问题,因为列名被指定为字符串,因此编码也很重要。一个例子可以是一个名为(注意元音变音符)的列名,然后你通过集合名称切换到,然后你尝试成为一个utf8编码的字符串,因为你的php文件是utf8编码的。它不起作用,您需要将字符串编码为latin1变体...现在你有各种各样的疯狂在发生。ütubelatinutf8$stmt->bindColumn('ütube', $var);ütube


推荐