character_set_connection的目的是什么?

21
我刚阅读了Stefan Gehrig对“SET CHARACTER SET utf8”是否必要?的回答,他比MySQL文档更深入地解释了字符集和排序规则方面查询解释和运行的阶段,但我仍然不太明白character_set_connection的目的,或者更具体地说,将语句从character_set_client转换为character_set_connection的目的。
为什么不直接在查询中使用character_set_client,并在与列值进行比较时直接从character_set_client转码到列的字符集?这个中间阶段的目的是什么?手册给出了比较文字的例子,但为什么你首先要这样做,更何况是在character_set_connection而不是character_set_client中进行?除非我的理解有误(例如"select 'somestr' = 'somestr' from x")。
谢谢。

你可能会得到一个不尽如人意的答案。很有可能是因为MySQL网络协议不支持传输服务器使用的编码,因此客户端需要知道如何解释从网络传输过来的字符,并且这种方式并没有被打破以保证兼容性。我只是在猜测,这不是一个答案。 - 0xCAFEBABE
感谢您的回复,也许我理解有误,但我认为 character_set_results 用于发送结果,并由客户端选择。据我所知,character_set_connection 只在 MySQL 内部使用。 - lm713
我相信这就是MySQL在接收数据时将使用的内容。 - Charlie Walton
4个回答

8
阅读答案和文档后,我只能想到一个使用character_set_connection(和_collation)的用例:

SELECT "StringA" < "StringB"

character_set_client 只对传输到服务器的内容有影响。 character_set_connection(以及与其不独立的排序规则)对语句的解释很重要。 "StringA"是否小于"StringB"取决于文字的字符集和排序规则。开发人员可能会选择与character_set_client不同的字符集/排序规则。
在实践中,character_set_connection大多数情况下不重要,因为文字与列进行比较,在这种情况下使用列的字符集和排序规则。
如果我说错了,请纠正我!
请参见https://dev.mysql.com/doc/refman/5.0/en/charset-connection.html
服务器在接收到语句后应该将其转换为哪种字符集?为此,服务器使用character_set_connection和collation_connection系统变量。它将客户端发送的语句从character_set_client转换为character_set_connection(除了具有_introducer_(如_latin1或_utf8)的字符串文字)。 collation_connection对于字面字符串的比较非常重要。对于与列值进行字符串比较,collation_connection并不重要,因为列具有自己的排序规则,其优先级更高。

1

1
这两者的不同之处在于,假定character_set_client是客户端发送语句时使用的字符集,因此是服务器用来解释语句的字符集,而character_set_connection是服务器用来处理语句的转换字符集。
如前所述,character_set_connection用于比较字面字符串。然而,这并不意味着等式两侧必须都是字面字符串。例如:
WHERE column_name = 'literal_string'
     (charset col)  (charset connection)

如果列和连接的字符集不同,则比较是非法的并会导致错误。
然后将结果(和响应消息)编码为character_set_results以发送回客户端。

这个答案忽略了问题的关键部分:为什么不直接从character_set_client进行转换? - goat
1
在比较操作期间没有隐式转换,因此如果客户端和服务器(列)处于不同的字符集中,则需要中介阶段。 - Hearth
我理解这个问题是从开发者的角度来看,为什么我们有这个额外选项以及它的作用是什么?如果你想从哲学上探讨服务器为什么会以这种方式运行,那最好向MySQL开发团队提问,因为这显然是一个设计决策。 - Hearth
根据我的理解,文档中的 'literal_string' 会被转换为 (charset col) 进行比较。这不是这种情况吗?感谢大家的评论。我没想到我会得到答案。 - lm713
我不认为这是隐式完成的,因为并非所有字符集都是可交换的。你能告诉我文档中你所提到的位置吗?我想要检查一下,看看我是否可以确认。 - Hearth
如果客户端使用character_set_client=utf8发送Unicode字符,但服务器使用character_set_connection=latin1解释查询,会怎么样呢?例如,在.NET中,Encoding库会用一个问号字符替换无法表示的字符。 - Andrew

-1
> <?php

// ... (create a connection to mysql) ...

mysql_query("SET character_set_results = 'utf8', character_set_client = 'utf8', character_set_connection = 'utf8', character_set_database = 'utf8', character_set_server = 'utf8'", $conn);

$re = mysql_query('SHOW VARIABLES LIKE "%character_set%";')or die(mysql_error());
while ($r = mysql_fetch_assoc($re)) 
{
    var_dump ($r); echo "<br />";
} 

exit;

?>

所有重要变量现在都是utf-8编码,我们可以安全地使用mysql_escape_string($var)进行INSERT或SELECT操作,而无需任何编码函数。


如果您通过“SET”查询设置连接变量,则不能安全地使用客户端转义,尤其是不要使用mysql_escape_string。您需要在客户端使用mysql_set_charset(),然后使用mysql_real_escape_string。或者干脆避免使用已弃用的mysql API。 - deceze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接