MySQL 存储 Emoji

2019-12-23

最近需要使用 SQLAlchemy 存弹幕的内容,但是遇到了存 emoji 的问题。

 

UPDATE: See https://docs.sqlalchemy.org/en/13/dialects/mysql.html#unicode for more info

utf8_bin?

一开始就套用存储中文姓名的那一套,使用utf8_bin的 collation,觉得 utf8 这种万能的东西直接用就行了。可谁知给我报错:

mysql.connector.errors.DatabaseError: 1366 (HY000): Incorrect string value: '\xE8\x86\x9C' for column 'text' at row 1
text

蛤?竟有如此操作?

utf8mb4_unicode_ci?

一波搜索之后就看到了使用utf8mb4_unicode_ci的 collation。于是就写:

text = db.Column(db.Unicode(256, collation='utf8mb4_unicode_ci'))
python

可惜并没有实质性效果

暴力二进制 #

utf8 解决不了,二进制存储总行了吧?

果然,存进去并没有问题。但是当要读取出来的时候又报了奇怪的错误:

TypeError: string argument without an encoding
python

明明是二进制怎么给我搞出来一个编码问题?

后期查阅资料发现,SQL 似乎有一个动态类型,每列的数据类型是建议值,并不强制。其结果就是我存一个二进制编码的字符串,他就真的以为是字符类型,并且数据库表里没有存编码,导致了问题出现。

疾病设计😠!!!

直接escape #

二进制也不行,全 escape 总可以了吧!

>>> text.encode('unicode_escape').decode()
>>> text.decode('unicode_escape').encode()
python

总算成功存储和读取了!

人人都说utf8mb4_unicode_ci #

为什么就是不行呢?

哦,还要改数据库 charset, collation

ALTER DATABASE databasename CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE tablename CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
sql

还要给 SQLAlchemy 加 ?charset=utf8mb4

Edit: 使用 SQLALCHEMY_ENGINE_OPTIONS.connect_args 不应该加 ?charset=utf8mb4,加完之后会优先认 ?charset=utf8mb4,导致 collation 默认 utf8mb4_0900_ai_ci (which is MySQL 8.0's default but not implemented in MySQL 5.7)

可是为什么还是不行?

mysql.connector.errors.DatabaseError: 1273 (HY000): Unknown collation: 'utf8mb4_0900_ai_ci'
python

我几几年用过这编码?

版本大坑 #

我找到了mysql-connector-python的官方文档:https://dev.mysql.com/doc/connector-python/en/connector-python-connectargs.html

collation 一栏中:

Argument NameDefaultDescription
collationutf8mb4_general_ai_ci (is utf8_general_ci in 2.xWhich MySQL collation to use. The 8.x default values are generated from the latest MySQL Server 8.0 defaults.

什么?8.0 的默认值?我们只有 5.7 呢!

虽然并不是utf8mb4_0900_ai_ci这种东西,我还是试着把链接数据库参数修改成utf8mb4_unicode_ci

SQLALCHEMY_ENGINE_OPTIONS:
    connect_args:
        collation: utf8mb4_unicode_ci
yaml

噫!成功了!

事实证明utf8mb4_0900_ai_ciutf8mb4_general_ai_ci应该是同义词一样的存在。

可是:

MySQL Connector/Python 8.0 is highly recommended for use with MySQL Server 8.0, 5.7, 5.6, and 5.5. Please upgrade to MySQL Connector/Python 8.0.

好一个recommended,就给我挖这种坑?版本问题害死人!

AllanChain
AllanChain
2020-03-19
SQLALCHEMY_ENGINE_OPTIONS:
    connect_args:
        charset: utf8mb4
        collation: utf8mb4_unicode_ci
yaml

这里指定编码。

Leave your comments and reactions on GitHub