将 UTF-8 编码的字符串插入 UTF-8 编码的 mysql 表失败,并显示“字符串值不正确”
Posted
技术标签:
【中文标题】将 UTF-8 编码的字符串插入 UTF-8 编码的 mysql 表失败,并显示“字符串值不正确”【英文标题】:Inserting UTF-8 encoded string into UTF-8 encoded mysql table fails with "Incorrect string value" 【发布时间】:2012-08-09 20:07:33 【问题描述】:将 UTF-8 编码的字符串插入 UTF-8 编码的表会给出不正确的字符串值。
PDOException: SQLSTATE[HY000]: 一般错误: 1366 不正确的字符串值: '\xF0\x9D\x84\x8E i...' 列 'body_value' 在第 1 行: INSERT INTO
我有一个????
字符,在mb_detect_encoding 声称是UTF-8 编码的字符串中。
我尝试将此字符串插入到 mysql 表中,该表定义为(除其他外)DEFAULT CHARSET=utf8
编辑: Drupal 总是使用 SET NAMES utf8
和可选的 COLLATE
(至少在与 MySQL 通信时)。
编辑 2: 一些看起来相关的更多细节。我从 PostgreSQL 数据库中获取一些文本。我将它粘贴到一个对象上,使用 mb_detect_encoding 来验证它是 UTF-8,然后使用 node_save 将对象保存到数据库中。因此,虽然有触发导入的 HTTP 请求,但数据并非来自浏览器。
编辑 3: 数据在两个表上非规范化:
SELECT character_set_name FROM information_schema.
COLUMNS
C WHERE table_schema = "[database]" AND table_name IN ("field_data_body", "field_revision_body") AND column_name = "body_value";
>+--------------------+
| character_set_name |
+--------------------+
| utf8 |
| utf8 |
+--------------------+
编辑 4: 这个角色有可能是“新人”吗?我对the relationship between unicode and UTF-8 有点模糊,但这个wikipedia article 暗示这个字符是最近才标准化的。
我不明白为什么会因为“字符串值不正确”而失败。
【问题讨论】:
该表上的字段是否使用 UTF-8 字符集定义? UTF-8 Database Problem的可能重复SELECT character_set_name FROM information_schema.`COLUMNS` C WHERE table_schema = "db_name" AND table_name = "table_name" AND column_name = "column_name";
提供了什么
MySQL 的 utf8
只是 BMP。它的utf8mb4
对应外界的UTF-8
(包含4字节字符)。
该错误是由于试图将 4 个字节塞进一个无法处理的字符集(即 MySQL 的“utf8”)。
【参考方案1】:
? (U+1D10E) 是在 BMP(基本多语言平面)之外(在 U+FFFF 之上)发现的字符 Unicode,因此不能用 UTF-8 以 3 个字节表示。 MySQL charset utf8 仅接受 UTF-8 字符,如果它们可以用 3 个字节表示。如果需要将其存储在 MySQL 中,则需要使用 MySQL charset utf8mb4。您需要 MySQL 5.5.3 或更高版本。您可以使用 ALTER TABLE 更改字符集,没有太大问题;因为它需要更多空间来存储字符,所以出现了一些可能需要您减小字符串大小的问题。见http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-upgrading.html。
【讨论】:
太好了,非常感谢。在进行这种特定类型的保存时更改表并执行“SET NAMES”,为我解决了这个问题。 旧版本的 MySQL 有解决方案吗? 如果他可以更改数据库,他肯定可以比使用 Postgresql 更轻松地升级 MySQL。 @JeromeJ - 5.5.3 是引入 utf8mb4 的时候。抱歉,没有 text 方法来存储 4 字节 UTF-8(非 BMP)字符。 @RickJames 我想我确实在保存字符串之前用它们的 HTML 字符替换了所有 4 字节的 UTF-8。【参考方案2】:要解决这个问题,首先将数据库字段更改为 utf8m4b 字符集。例如:
ALTER TABLE `tb_name` CHANGE `field_name` `field_name` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL;
然后在您的数据库连接中,将 driver_options 设置为 utf8mb4。例如,如果您使用 PDO
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8mb4', 'username', 'password');
或在 zend 框架 1.2 中
$dbParam = array('host' => 'localhost', 'username' => 'db_user_name',
'password' => 'password', 'dbname' => 'db_name',
'driver_options' => array(
'1002' => "SET NAMES 'utf8mb4'",
'12' => 0 //this is not necessary
)
);
【讨论】:
这里的 1002 和 12 代表什么? 它们是PDO mysql中driver_options的选项。您可以参考这里了解更多详情php.net/manual/en/ref.pdo-mysql.php PDO::MYSQL_ATTR_INIT_COMMAND (1002) 和 PDO::FETCH_KEY_PAIR (12)。与问题相关的 FETCH_KEY_PAIR 是否必要?【参考方案3】:【参考方案4】:我修复了错误: SQLSTATE[HY000]:一般错误:1366 字符串值不正确...... 用这个方法:
我使用 utf8mb4_unicode_ci 作为数据库 为所有表设置 utf8mb4_unicode_ci
为列设置长博客数据类型(不是文本,长文本......您需要大数据类型来存储 4 个字节的内容)
现在好了。 如果你使用laravel,继续编辑config/database.php
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
如果您使用函数 strtolower,请将其替换为 mb_strtolower
注意:你必须把<meta charset="utf-8">
放在你的head标签上
【讨论】:
以上是关于将 UTF-8 编码的字符串插入 UTF-8 编码的 mysql 表失败,并显示“字符串值不正确”的主要内容,如果未能解决你的问题,请参考以下文章