PyMySQL 插入二进制数

2016-12-01 10:28:45 +08:00
 XIVN1987
PyMySQL 执行 SQL 语句的函数如下:
def query(self, sql, unbuffered=False):
if isinstance(sql, text_type) and not (JYTHON or IRONPYTHON):
if PY2:
sql = sql.encode(self.encoding)
else:
sql = sql.encode(self.encoding, 'surrogateescape')
self._execute_command(COMMAND.COM_QUERY, sql)

PyMySQL 会把它要执行的 SQL 语句都执行一下 encode ,,这样我插入二进制数据时 SQL 语句中的二进制数据字节也会因此而被修改,插入数据库的数据显然就不是我要插入的数据了,,请问这种情况怎么办?? PyMySQL 没有办法控制不对要执行的 SQL 语句 encode 吗?
3957 次点击
所在节点    Python
21 条回复
mhycy
2016-12-01 10:29:55 +08:00
BASE64 编码后插入
XIVN1987
2016-12-01 10:57:44 +08:00
@mhycy
多谢,这种方法确实可行,可是却增加了 1/4 的数据量,而且存入和取出时还需要编解码,所以我还是希望能够找到直接存入二进制数据的方法
mhycy
2016-12-01 11:08:30 +08:00
@XIVN1987
刚刚看了下源码,无解
问题不仅仅在 query 在 query 之前的参数化拼接也有转码

可以尝试直接调用_execute_command 这个“私有”函数

PS. 同时获知这货不支持参数化查询
XIVN1987
2016-12-01 11:37:25 +08:00
@mhycy
直接调用_execute_command 我试过了,报错“命令不同步”,所以绕过编码直接调用底层函数可能要写很多代码才行,,所以这种方法不可行

不过我倒发现另外一个可行的方法,就是建立连接的时候 connect 函数参数 charset 设置为''而非'uft-8',这样就算执行编码语句也不会改变数据,,可问题是如果这样的话其他需要编码的数据字段就得全部手动执行编码,非常麻烦

所以我又想到一个另类的方法,建立两个 connect ,,一个 charset 为'utf-8'用来执行无二进制数据的 SQL 语句,一个 charset 为''专门执行有二进制数据的 SQL 语句

不过这也太不优雅了,,我想 PyMySQL 不至于只能这么做吧
XIVN1987
2016-12-01 11:44:02 +08:00
@mhycy
我想我找到方法了:
在插入二进制数据之前调用 con.set_charset('lati-1'),这样编码就不会改变数据
在插入二进制数据之后调用 con.set_charset('utf-8'),
lerry
2016-12-01 11:46:45 +08:00
楼主看这个
https://github.com/PyMySQL/PyMySQL/blob/master/pymysql/tests/test_basic.py

"binary\x00data".encode(conn.charset)

PyMySQL 肯定是能处理好二进制的,这是个基本需求嘛
mhycy
2016-12-01 11:57:42 +08:00
@XIVN1987

你这是取巧办法啊
每次都调用一次 encode 让人不放心..囧

@lerry 依赖底层的编码处理,能用,但不靠谱
mhycy
2016-12-01 12:00:20 +08:00
补充:
我认为还是趁早放弃在 MySQL 放二进制文件比较靠谱,要是数据小的话 base64 也不会增加太多空间消耗。
从可靠性来看是更优选。
XIVN1987
2016-12-01 12:31:04 +08:00
@lerry
比如二进制数'\xF0\xA0'放到 SQL 语句中它是
"INSERT INTO ........... '\xF0\xA0' ......"
可是 PyMySQL 在执行这条 SQL 语句前会对这条语句执行 encode('utf-8'),语句就变成了
"INSERT INTO ........... '\xF0\xC2\xA0' ......"
看到没,,数据变了!!!这样 2 个字节的数据插入到 MySQL 里面就变成了 3 个字节!!!
sujin190
2016-12-01 12:44:28 +08:00
其实你再看一下源码,其中是只有你传过去的 sql 是 unicode 的时候才编码的,你可以自己拼接 sql ,然后编码成 utf-8 字符串传进去就不会再进行编码了
sujin190
2016-12-01 12:45:51 +08:00
而且如果你发送的 sql 是 unicode ,为了能在网络上发送,编码成二进制数据是很正常的啊,并没有什么问题
XIVN1987
2016-12-01 12:55:41 +08:00
@sujin190
多谢指点,如你所说,确实只有当 sql 是 unicode ( Py3 下的 str )时才会执行 encode('utf-8'),所以在执行 sql 前执行一下编码变成 bytes 就不会在被编码了,,不过不能编码成 utf-8 再传,而是用 latin-1 编码再传
TaMud
2016-12-01 15:06:23 +08:00
execute

满足你
mhycy
2016-12-01 15:34:59 +08:00
@TaMud

别上来就乱答,看过源码再说话,从 execute 开始到最终 query 好几层 encode 在上面
TaMud
2016-12-01 17:22:49 +08:00
我错了,我不该帮忙的
你折腾你快乐,可惜没脑子
TaMud
2016-12-01 17:25:03 +08:00
我以后要记得教训,不能帮智障,不然还会被骂

我不由想起一句话:脑子是个好东西,可惜你没有
TaMud
2016-12-01 17:26:33 +08:00
我还不由想起一个故事
A:师傅,你的刀不行呀,你看,这个骨头砍了半天砍不断
B:你刀拿反了
TaMud
2016-12-01 17:28:30 +08:00
A:师傅,你不懂不要瞎说,刀不是砍骨头的嘛
B:你刀拿反了
A:师傅,是不是你的刀是伪劣产品
B:你刀拿反了

我一笑而过
XIVN1987
2016-12-01 17:35:23 +08:00
@TaMud
知之为之啊少年,人家好心给你指出错误,你不感谢也就罢了,竟然还嘲讽。。。

cursor.execute()最终也是要调用 connection.query()的
TaMud
2016-12-01 17:40:41 +08:00
你刀拿反了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/324500

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX