【问题标题】:SQLAlchemy/MySQL binary blob is being utf-8 encoded?SQLAlchemy/MySQL 二进制 blob 是 utf-8 编码的吗?
【发布时间】:2016-04-06 05:54:20
【问题描述】:

我正在使用 SQLAlchemy 和 MySQL,以及一个 files 表来存储文件。该表定义如下:

mysql> show full columns in files;
+---------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
| Field   | Type         | Collation       | Null | Key | Default | Extra | Privileges                      | Comment |
+---------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+
| id      | varchar(32)  | utf8_general_ci | NO   | PRI | NULL    |       | select,insert,update,references |         |
| created | datetime     | NULL            | YES  |     | NULL    |       | select,insert,update,references |         |
| updated | datetime     | NULL            | YES  |     | NULL    |       | select,insert,update,references |         |
| content | mediumblob   | NULL            | YES  |     | NULL    |       | select,insert,update,references |         |
| name    | varchar(500) | utf8_general_ci | YES  |     | NULL    |       | select,insert,update,references |         |
+---------+--------------+-----------------+------+-----+---------+-------+---------------------------------+---------+

MEDIUMBLOB 类型的内容列是存储文件的位置。在 SQLAlchemy 中,该列被声明为:

__maxsize__ = 12582912 # 12MiB                                                                                                                              
content = Column(LargeBinary(length=__maxsize__))                           

我不太确定 SQLAlchemy 的 BINARY 类型和 LargeBinary 类型之间的区别。或者MySQL的VARBINARY类型和BLOB类型的区别。我不太确定这是否重要。

问题:每当我在该表中存储一个实际的二进制文件,即 Python bytesb'' 对象时,我都会收到以下警告

.../python3.4/site-packages/sqlalchemy/engine/default.py:451: Warning: Invalid utf8 character string: 'BCB121'
  cursor.execute(statement, parameters)

我不想忽略警告,但文件似乎完好无损。如何优雅地处理此警告,如何解决其原因?

旁注: This question 似乎是相关的,它似乎是一个 MySQL 错误,它试图将 所有 传入数据转换为 UTF-8 (@ 987654328@).

【问题讨论】:

  • 您似乎正在运行 Python。两个“旁注”指的是 PHP 和 Perl 问题。 Python 中的某些内容未能满足您使用“blob”数据的请求。
  • @RickJames:是的,都是 Python。然而,旁注中的“this answer”链接似乎表明这是一个 MySQL 问题。如果这是一个 Python 问题,我仍然想了解我在这里缺少什么......
  • 如果 client(PHP、Python 等)将字符串视为“字符”,则可能会出现此问题。如果它将其视为任意“字节”,则不会出现问题。存储到 MySQL BLOB 不会进行 utf8 检查;存储到TEXT 中。
  • 所以,我声称,客户端中的一些细节丢失了。 (或者 Alchemy 无法处理 BLOBs。)
  • @RickJames:这是一个b' ' 对象,即二进制字节......

标签: mysql python-3.x utf-8 sqlalchemy blob


【解决方案1】:

原来这是驱动程序问题。显然,默认的 MySQL 驱动程序在 Py3 和 utf8 支持上出现问题。将cymysql 安装到虚拟 Python 环境中解决了这个问题并且警告消失了。

修复: 判断 MySQL 是通过 socket 还是 port 连接(参见here),然后相应地修改连接字符串。在我使用套接字连接的情况下:

mysql+cymysql://user:pwd@localhost/database?unix_socket=/var/run/mysqld/mysqld.sock

否则使用port 参数。

编辑:虽然上面修复了编码问题,但它引发了另一个问题:blob 大小。由于a bug in CyMySQL 大于 8M 的 blob 无法提交。切换到PyMySQL 解决了这个问题,尽管它似乎有一个带有大斑点的similar issue

【讨论】:

  • 实际上,显然是 MySQL 服务器生成了此警告,解决方法是使用 _binary 表示不应解释您插入的内容。见bugs.mysql.com/bug.php?id=79317
  • @Wodin:表示将binary_prefix=true添加到连接字符串中,另见this discussion
【解决方案2】:

不确定,但您的问题可能与我几年前在 python 2.7 中遇到的问题有相同的根源:https://stackoverflow.com/a/9535736/68998。简而言之,Mysql 的界面无法让您确定您使用的是真正的二进制字符串还是二进制排序规则中的文本(因为缺少区分大小写的 utf8 排序规则而使用)。因此,Mysql 绑定具有以下选项:

  • 将所有字符串字段作为二进制字符串返回,解码交给您
  • 只解码没有二进制标志的字段(当一些字段是unicode而其他字段是str时非常有趣)
  • 可以选择将所有字符串字段强制解码为unicode,甚至是真正的二进制文件

我的猜测是,在您的情况下,第三个选项是在底层 Mysql 绑定中启用的。第一个嫌疑人是您的连接字符串(连接参数)。

【讨论】:

  • 我当前的连接字符串是:mysql://user@localhost/database?charset=utf8。根据documentation charset 选项“指定应该用于对发送到服务器的所有查询进行编码的字符集。”嗯——编码所有个查询?
猜你喜欢
  • 2015-12-07
  • 2014-04-09
  • 2013-01-26
  • 2013-08-09
  • 2016-05-23
  • 2022-12-15
  • 2019-02-03
  • 2011-04-12
  • 2020-05-07
相关资源
最近更新 更多