Fab*_*bio 6 mysql character-set utf-8 encoding
我遇到了类似于这个问题的情况,即我正在使用一个旧数据库,该数据库在 latin1 表中包含 UTF8 内容(我知道非常难看)。
\n\n现在我正在从一个完全 utf8 的新应用程序获取新数据,并与其数据库一起使用。为了支持其他遗留系统,应用程序还在遗留表中写入其 utf8 数据的副本。据我所知,只要您读回并将这些数据显示为 UTF8,就应该可以在 latin1 表中写入 utf8 内容。有很多教程解释了如何长期解决这种情况,但我宁愿不应用它们,除非绝对必要(遗留系统将很快被解雇,我不希望有停机时间来解决这个问题,如果可能的)
\n\n这是一个最小的 SQL 脚本,它重现了我的问题:
\n\nCREATE TABLE `articles` (\n `content` mediumtext NOT NULL,\n FULLTEXT KEY `content` (`content`)\n) ENGINE=MyISAM DEFAULT CHARSET=latin1;\n\nSET NAMES utf8;\nSET CHARACTER SET utf8;\n-- Turkish word for Croatia, second char is \\xC4\\xB1\nINSERT INTO `articles` (`content`) VALUES (\'H\xc4\xb1rvatistan\');\nRun Code Online (Sandbox Code Playgroud)\n\n在我的系统中,我没有从 MySQL 收到错误,但在INSERT语句之后,该单词的第二个字符被默默删除并替换为文字?(\'\\x3F\')。
mysql> SELECT content, HEX(content), HEX(\'H\xc4\xb1rvatistan\') FROM articles;\n+-------------+------------------------+--------------------------+\n| content | HEX(content) | HEX(\'H\xc4\xb1rvatistan\') |\n+-------------+------------------------+--------------------------+\n| H?rvatistan | 483F72766174697374616E | 48C4B172766174697374616E |\n+-------------+------------------------+--------------------------+\nRun Code Online (Sandbox Code Playgroud)\n\n但是,如果我将相同的脚本粘贴到http://sqlfiddle.com/上,当我按“构建架构”时会收到错误消息,其中指出:
\n\nIncorrect string value: \'\\xC4\\xB1rvat...\' for column \'content\' at row 1\nRun Code Online (Sandbox Code Playgroud)\n\n为什么在我的系统上,无效的 utf8 字符被简单地删除而我没有收到任何错误?是否有任何 mysql 配置值可以启用以避免这种情况?
\n\n在我当前的 latin1 (带有 utf8 内容)表中允许任何类型的 char 的最简单方法是什么?我有很多内容,我希望避免转储内容并使用其他字符集重新导入等解决方案
\n我做了一些尝试来深入研究这个问题,结果如下。
\n\n当您设置连接字符集(即SET NAMES utf8)时,MySQL 会透明地为您处理编码转换。例如,如果我\xc3\xa0 (\\xE0 in latin1 \\xC3A0 in utf8)使用 UTF8 连接在 latin1 表中插入 a ,它会读取 UTF 8 值并将其存储在表中\\xE0
mysql> SELECT HEX(\'\xc3\xa0\');\n+-----------+\n| HEX(\'\xc3\xa0\') |\n+-----------+\n| C3A0 |\n+-----------+\n\nmysql> INSERT INTO articles VALUES(50001, \'\xc3\xa0\');\nQuery OK, 1 row affected (0,00 sec)\n\nmysql> SELECT content, HEX(content) FROM articles WHERE id_p = 50001;\n+---------+--------------+\n| content | HEX(content) |\n+---------+--------------+\n| \xc3\xa0 | E0 |\n+---------+--------------+\n1 row in set (0,00 sec)\nRun Code Online (Sandbox Code Playgroud)\n\n当我将无效的 utf8 字符插入到 latin1 中时,它会将它们替换为问号,如我在原始问题中所示。
\n\n为了解决我的问题,我必须在原始表上运行此命令(实际上我在它的一个小副本上尝试过)。它负责更改字符集、排序规则并转换现有数据。我用一个字符进行记录,该字符的 latin1 和 utf8 编码不同
\n\nmysql> select HEX(BINARY SUBSTRING(content, 17, 1)), SUBSTRING(content, 17, 1) from articles where id_p = 40\\G\n*************************** 1. row ***************************\nHEX(BINARY SUBSTRING(content, 17, 1)): 93\n SUBSTRING(content, 17, 1): \xe2\x80\x9c\n1 row in set (0,00 sec)\n\nmysql> ALTER TABLE `articles` CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;\nQuery OK, 34905 rows affected (1 min 10,73 sec)\nRecords: 34905 Duplicates: 0 Warnings: 0\n\nmysql> select HEX(BINARY SUBSTRING(content, 17, 3)), SUBSTRING(content, 17, 3) from articles where id_p = 40\\G\n*************************** 1. row ***************************\nHEX(BINARY SUBSTRING(content, 17, 1)): E2809C\n SUBSTRING(content, 17, 1): \xe2\x80\x9c\n1 row in set (0,00 sec)\nRun Code Online (Sandbox Code Playgroud)\n\n转换后,\xe2\x80\x9c内容中的 char 被替换为 utf8 编码,所有数据仍然可读。转换还将content列类型从更改MEDIUMTEXT为LONGTEXt,因为 latin1 每个字符使用 1 个字节,而 utf8 每个字符最多使用 3 个字节以避免数据截断。
现在我正在尝试将无效的 utf8 字符插入到转换后的表中,并且得到了不同的结果。似乎无效(或不支持 4 字节)utf 字符只是从存储值中删除并带有警告(仅在启用警告时显示)
\n\n$ mysql --show-warnings\n\nmysql> INSERT INTO articles VALUES(90000, 0xC328);\nQuery OK, 1 row affected, 1 warning (0,00 sec)\n\nWarning (Code 1366): Incorrect string value: \'\\xC3(\' for column \'content\' at row 1\nmysql> SELECT 0xf09f8eb6;\n+------------+\n| 0xf09f8eb6 |\n+------------+\n| |\n+------------+\n1 row in set (0,00 sec)\n\nmysql> INSERT INTO articles VALUES(90001, 0xf09f8eb6);\nQuery OK, 1 row affected, 1 warning (0,00 sec)\n\nWarning (Code 1366): Incorrect string value: \'\\xF0\\x9F\\x8E\\xB6\' for column \'content\' at row 1\nRun Code Online (Sandbox Code Playgroud)\n\n之后,我发现在我的原始示例中,如果启用它们,也会显示警告:
\n\n-- With warnings enabled\nmysql> INSERT INTO `articles` VALUES (50000, \'H\xc4\xb1rvatistan\');\nQuery OK, 1 row affected, 1 warning (0,00 sec)\n\nWarning (Code 1366): Incorrect string value: \'\\xC4\\xB1rvat...\' for column \'content\' at row 1\nRun Code Online (Sandbox Code Playgroud)\n\n最后,要触发错误而不仅仅是警告(以避免数据丢失),只需更改会话或全局(在服务器级别)的SQL 模式
\n\nmysql> SET SESSION sql_mode = \'TRADITIONAL\';\nQuery OK, 0 rows affected (0,00 sec)\n\nmysql> INSERT INTO `articles` VALUES (50000, \'H\xc4\xb1rvatistan\');\nERROR 1366 (HY000): Incorrect string value: \'\\xC4\\xB1rvat...\' for column \'content\' at row 1\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
15110 次 |
| 最近记录: |