Python3 MysqlDBからMariaDBに絵文字を保存しようとすると”Warning: (1366, “Incorrect string value: ‘\xF0\x9F\x98\x8A\xF0\x9F…’ for column ‘lunch’ at row 1”)”のようなエラーが発生して、保存できなかった。経緯を調べると、現在のUTF-8は4byte利用しているが、MariaDBは歴史的経緯により3byteのUTF-8までしか対応していなかった。絵文字で拡張された部分が4byte利用するということのようだ。

この場合以下の対応が必要となる。

  • MariaDBの設定
  • データベースのcharcterset更新
  • Python3 MysqlDBのcharcterset変更

MariaDBの設定

/etc/my.confまたは、各項目を/etc/my.conf.d/[server.conf|client.conf]に分けて記述する。

[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

設定後mariadbを再起動すれば設定完了です。再起動後以下のコマンドで確認してください。以下のようになっていれば設定は成功しています。

mysql> SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
+--------------------------+--------------------+
| Variable_name | Value |
+--------------------------+--------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| collation_connection | utf8mb4_unicode_ci |
| collation_database | utf8mb4_unicode_ci |
| collation_server | utf8mb4_unicode_ci |
+--------------------------+--------------------+
10 rows in set (0.00 sec)

データベースCharsetの変更

以下のように各データベース・テーブル等に設定してください。例のSQL分はDB名やテーブル名がサンプルになっています。特にカラムの場合にはカラム名が変更されてしまうので、注意してください。

# 各DBで行う:
ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

# 各テーブル(テーブルにcharasetが設定されていたら):
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

# 各カラム(設定していたら):
ALTER TABLE table_name CHANGE column_name column_name VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;


Pytho3 MysqlDBの設定変更

connect時にcharsetをutf8としていたものを、utf8mb4に変更してください。

        self.db = MySQLdb.connect(
            host=Mconfig.strDBhost,
            db=self.strDBname,
            user=self.strDBuser,
            passwd=self.strDBpass,
            charset="utf8mb4")

以上で完了です。絵文字が保存できるようになったことを確認してみてください。