我在Debian 8机器上使用Perl 5.20.2和MySQL 5.5.57。我最近发现MySQL的utf8表仅限于三字节字符串。因此,我无法存储表情符号。 所以,我尝试了utfmb4表来解决这个问题。我在mysql客户端内部将表从utf8更改为utf8mb4:
ALTER DATABASE `mydb` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
ALTER TABLE `mydb`.`mytable` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `mydb`.`mytable` CHANGE `object` `object` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
在mytable中存储数据似乎有效,至少我可以在phpMyAdmin中看到预期的表情符号。但是,当从表中读取时,我收到一个包含3个不可打印的字符的4个字符的结果。以下程序应该打印两次相同的表情符号:
#!/usr/bin/perl
use 5.10.1;
use warnings;
use strict;
use DBI;
binmode(STDOUT, ':utf8');
my $object = "\x{1F600}";
my $hd_db = DBI->connect('DBI:mysql:mydb:localhost', 'user', 'password');
$hd_db->do('SET NAMES utf8mb4');
# cleanup
my $delete = $hd_db->prepare("DELETE FROM mytable");
$delete->execute;
my $insert = $hd_db->prepare("INSERT INTO mytable (object) VALUES ('" . $object . "')");
$insert->execute;
my $select = $hd_db->prepare("SELECT * FROM mytable");
$select->execute;
my $row = $select->fetchrow_hashref;
say $object;
say $row->{'object'};
预期产出:
实际输出:
�
对我来说似乎是一个错误。有什么建议如何解决它?
编辑:从mysql客户端中选择数据也会显示预期的表情符号
mysql> SET SESSION CHARACTER_SET_CLIENT = utf8mb4;
mysql> SET SESSION CHARACTER_SET_RESULTS = utf8mb4;
mysql> SELECT * FROM mytable;
+--------+
| object |
+--------+
| |
+--------+
答案 0 :(得分:3)
你告诉MySQL使用UTF-8进行通信,但你还需要告诉DBD :: mysql解码数据(或自己动手)。
你想要
my $dbh = DBI->connect('DBI:mysql:mydb:localhost', 'user', 'password', {
mysql_enable_utf8mb4 => 1,
})
or die($DBI::errstr);
相当于
my $dbh = DBI->connect('DBI:mysql:mydb:localhost', 'user', 'password')
or die($DBI::errstr);
$dbh->do('SET NAMES utf8mb4')
or die($dbh->errstr);
$dbh->{mysql_enable_utf8mb4} = 1;
答案 1 :(得分:1)
解决方法是让MySQL将所有内容视为字节并在应用程序中进行编码。
use Encode qw(encode decode);
my $object = "\x{1F600}";
my $hd_db = DBI->connect('DBI:mysql:mydb:localhost', 'user', 'password');
$hd_db->do('SET NAMES latin1');
...
my $insert = $hd_db->prepare("INSERT INTO mytable (object) VALUES ('" .
encode("UTF-8",$object) . "')"); # or equiv statement with placeholders
$insert->execute;
...
my $select = $hd_db->prepare("SELECT * FROM mytable");
$select->execute;
my $row = $select->fetchrow_hashref;
say $object;
say decode("UTF-8",$row->{'object'});
答案 2 :(得分:0)
"\x{1F600}";
是“Unicode”,而不是“utf8”。它们是相关的,但它们不是相同的编码。
你需要UTF-8
(非mysql世界称之为)和utf8mb4
(正如MySQL所称)。
是十六进制
F09F9880
(在utf8mb4中);如果您通过😀
(“Mojobake”)进行转换,则为CHARACTER SET latin1
请运行SELECT HEX(object) ...
以查看是否获得了这4个十六进制字节或其他内容。然后,我们将知道是关注INSERT
还是SELECT
。
你说“实际输出” - 但这是什么?一个网页?是否为UTF-8
配置了?或者是其他东西?如果是命令行窗口,请确保将其设置为UTF-8。在Windows中,通过chcp 65001
完成。
你提到了
mysql> SET SESSION CHARACTER_SET_CLIENT = utf8mb4;
mysql> SET SESSION CHARACTER_SET_RESULTS = utf8mb4;
这只是需要设置的3个中的2个。最好只做
SET NAMES utf8mb4;