Как подключиться к MySQL с помощью UTF8 в perl script?

В двух словах:

В Perl- Script: как мне подключиться к MySQL таким образом, который позволяет передавать четырехбайтовый символ Unicode U + 1F61C ( "😜" ) из perl script в MySQL-таблицу, где этот символ должен быть сохранен?

Использование {mysql_enable_utf8 => 1} не решает проблему.

Подробнее:

У меня точно такая же проблема, как описано в вопросе ERROR 1366 (HY000): неправильное строковое значение: '\ xF0\x9F\x98\x9C' для столбца 'comment' at строка 1 и даже с одним и тем же символом Юникода (😜 = U + 1F61C = ЛИЦО С ВСТРОЕННЫМ ТОНКОЙ И ВЕКОВОЙ ГЛАЗА) который выдает сообщение об ошибке

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.
    ✅checked

  • Установить символ таблицы 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.
    ✅checked

  • Включить UTF8 в вашем подключении MySQL.
    Кажется, это проблема. Ответ на другой вопрос гласит:

    SET NAMES utf8 или используйте параметр при подключении, который аналогичным образом включает его.

Я не знаю, как SET NAMES utf8 в perl script, поэтому я сделал это, как я это делал за последние годы. Я думаю, что это "вариант при подключении, который так же позволяет это".
Это в конце длинной строки, начинающейся с 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.

Что я делаю неправильно?
Как я могу сделать это лучше?

Ответы

Ответ 1

Проблема заключается в команде SET NAMES utf8. В MySQL набор символов utf8 не является действительно utf8, он поддерживает символы только с 3 байтами, и этот символ имеет 4 байта:

Набор символов utf8 в MySQL имеет следующие характеристики:

• Нет поддержки дополнительных символов (только символы BMP).

• Максимум три байта на многобайтовый символ.

Истинным utf8 является utf8mb4, который вы используете как набор символов в самом поле. Итак, используйте SET NAMES utf8mb4

Итак, из Perl вы должны использовать {mysql_enable_utf8mb4 => 1} вместо {mysql_enable_utf8 => 1}.