如何在 perl 脚本中使用 UTF8 连接到 MySQL?

Posted

技术标签:

【中文标题】如何在 perl 脚本中使用 UTF8 连接到 MySQL?【英文标题】:How to connect to MySQL using UTF8 within a perl script? 【发布时间】:2016-12-29 23:14:54 【问题描述】:

简而言之:

在 Perl 脚本中:如何以允许将四字节 unicode 字符 U+1F61C(“????”)从 perl 脚本传输到 mysql 表的方式连接到 MySQL字符应该被存储?

使用mysql_enable_utf8 => 1 并不能解决问题。

详细说明:

我遇到了与问题 ERROR 1366 (HY000): Incorrect string value: '\xF0\x9F\x98\x9C' for column 'comment' at row 1 中描述的完全相同的问题,即使使用相同的 Unicode 字符 (???? = U+1F61C = FACE WITH STUCK-OUT TONGUE AND WINKING EYE) 也会产生错误消息

DBD::mysql::st execute failed: Incorrect string value: '\xF0\x9F\x98\x9C' for column ...

但我不使用 php,我使用 Perl。

另一个问题中接受的答案是:

运行 MySQL 5.5 或更高版本。 我检查版本:

mysql> select version();
+-------------------------+
| version()               |
+-------------------------+
| 5.7.13-0ubuntu0.16.04.2 |
+-------------------------+

所以是 5.7 比 5.5 晚。 ✅检查

将表格的字符设置为utf8mb4 我检查了我的数据库、我的表甚至报告的列的字符集:

mysql> SELECT default_character_set_name FROM information_schema.SCHEMATA 
    -> WHERE schema_name = "myDatabase";
+----------------------------+
| default_character_set_name |
+----------------------------+
| utf8mb4                    |
+----------------------------+

mysql> SELECT CCSA.character_set_name FROM information_schema.`TABLES` T,
    ->        information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` CCSA
    -> WHERE CCSA.collation_name = T.table_collation
    ->   AND T.table_schema = "myDatabase"
    ->   AND T.table_name   = "myTable";
+--------------------+
| character_set_name |
+--------------------+
| utf8mb4            |
+--------------------+

mysql>   SELECT character_set_name FROM information_schema.`COLUMNS` 
    -> WHERE table_schema = "myDatabase"
    ->   AND table_name   = "myTable"
    ->   AND column_name  = "myColumn";
+--------------------+
| character_set_name |
+--------------------+
| utf8mb4            |
+--------------------+

所以我的数据库、我的表和报告的列都使用字符集utf8mb4。 ✅检查

在您的 MySQL 连接上启用 UTF8。 这似乎是问题所在。 answer to the other question 说:

SET NAMES utf8,或在连接时使用类似启用它的选项。

我不知道如何在 perl 脚本中 SET NAMES utf8,所以我按照过去几年的方式进行了操作。我认为这是“连接时类似启用它的选项”。 它位于以my $dbh = DBI->connect 开头的长行的末尾:

#!/usr/bin/perl -w
use strict;
use warnings;
use utf8;
use Encode;
use DBI;
binmode STDOUT, ":utf8";

#Here I connect using the parameter mysql_enable_utf8 (create database handle):
my $dbh = DBI->connect('DBI:mysql:database=myDatabase;host=localhost','aUser','aPassword',mysql_enable_utf8 => 1);

#Prepare the statement (create statement handle):
my $sth = $dbh->prepare('INSERT INTO `myTable` (`myColumn`) VALUES(?);');

#This doesn't work: 
$sth->execute('????');

#This doesn't work either: 
$sth->execute(encode_utf8('????'));

#end processing:
$dbh->disconnect();
exit(0);

两次执行都抛出相同的错误(只有最后的行号改变):

DBD::mysql::st execute failed: Incorrect string value: '\xF0\x9F\x98\x9C' for column 'myColumn' at row 1 at myTestScript.pl line 16.

我做错了什么? 我怎样才能做得更好?

【问题讨论】:

我希望所有问题都像这样写... @Shadow:我花了大约 1 个小时,也许这就是为什么几乎没有人这样做的原因。 好吧,每个人都应该遵循这个例子。我只用了 5 分钟写下答案,因为问题清晰且结构合理。 【参考方案1】:

问题在于SET NAMES utf8 命令。在 MySQL 中,utf8 字符集并不是真正的 utf8,它是supports characters up 3 bytes only,并且有问题的字符有 4 个字节:

MySQL中的utf8字符集有以下特点:

• 不支持补充字符(仅限 BMP 字符)。

• 每个多字节字符最多三个字节。

真正的 utf8 是您在字段本身中用作字符集的 utf8mb4。所以,使用SET NAMES utf8mb4

所以在 Perl 中你应该使用 mysql_enable_utf8mb4 => 1 而不是 mysql_enable_utf8 => 1

【讨论】:

谢谢!我刚刚在您的答案末尾添加了关于 mysql_enable_utf8mb4 的注释,因为这似乎是您在 Perl 中说 SET NAMES utf8mb4 的方式。 我必须相信你,因为我不太懂 perl,只懂 MySQL :)

以上是关于如何在 perl 脚本中使用 UTF8 连接到 MySQL?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Perl 连接到 MySQL?

如何使用 Perl 通过 TCP 和 UDP 连接到远程机器?

Perl 无法在 cronjob 中连接到 Oracle DB

如何检测标准输出是不是连接到 Perl 中的 tty?

在 Perl 中使用 DBI 连接到 Oracle 数据库,在 Windows 中出现 ERROR OCIEnvNlsCreate

如何从 perl 连接到 gmail?