【问题标题】:Python 3 SQL Binary Data INSERT without ConversionPython 3 SQL 二进制数据插入而不转换
【发布时间】:2020-04-06 19:05:11
【问题描述】:

我正在使用带有 mysqlclient 的 MySql 和 Python 3.6/3.8 来维护具有二进制字段的数据库。该代码是在我使用 Python 2.7 之前构建的,用于直接插入包含二进制数据的字段。例如,表格看起来像

+-------------------------+--------------------------------------------------------------------+------+-----+------------+-------+
| Field                   | Type                                                               | Null | Key | Default    | Extra |
+-------------------------+--------------------------------------------------------------------+------+-----+------------+-------+
| license_id              | varchar(36)                                                        | NO   | PRI | NULL       |       |
| data                    | binary(32)                                                         | NO   | UNI | NULL       |       |
+-------------------------+--------------------------------------------------------------------+------+-----+------------+-------+

插入命令看起来像:

 dbconn.execute("""INSERT into datatable (
                            license_id,
                            data)
                        VALUES ("{:s}", "{:s}")
                    """.format(
                        str(self._license_id),                        
                        escape_string(self._data)))

这将导致 Python 2.7 直接在命令中插入二进制数据,例如

 INSERT into datatable (license_id, data) VALUES ("XXX-XXX-52", "������C�...\r�x�b24�B")

但在 Python 3 中,数据是字节数组类型,不能插入到字符串中,尝试对其进行解码会导致:

escape_string(self._auth_hash).decode()
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd0 in position 5: invalid continuation byte

其他问题似乎表明解决此问题的可行途径是将二进制转换为十六进制(例如here),但是有没有办法像原始代码一样插入到 Python 3 unicode 字符串中而不会出错?

删除"{:s}" 周围的引号并使用binascii.b2a_hex(self._data) 会出现相同的意图,但尚不清楚这将具有完全相同的行为或是否会出现问题。我预计这是一个反复出现的问题,并且正在寻找副作用最小的解决方案。

【问题讨论】:

    标签: python mysql sql python-3.x python-2.7


    【解决方案1】:

    这可以通过让数据库连接器自动处理转义而不是使用手动转义和字符串格式化的组合来完成。

    鉴于这些字节(Python 2.7 将接受 b"" 形式为 str):

    bs = b"\xec\xa6\x8fH~\x83\\\xfeoc\x92\xf9\xad\xe6'\xc6\x1a\x00j\x99$x\xd9\xda\xef\x0c\x080rm\xe6\xcd"
    

    问题中的代码和此 Python 3 代码会将相同的值插入到 data 列中。

    conn = MySQLdb.connect(db='test')
    cur = conn.cursor()
    cur.execute(
            """INSERT INTO datatable (license_id, data) VALUES (%s, %s)""",
            ('python3', bs))
    conn.commit()
    conn.close()
    

    【讨论】:

    • 我们如何对更新查询进行相同的处理?我有一个这样的更新查询:query = """UPDATE files SET file = '%s' WHERE id = %d""" % (self.file, self.id) 其中self.filebytes 数据类型
    • 可能通过不使用字符串格式 - 尝试 query = """UPDATE files SET file = '%s' WHERE id = %s""", (self.file, self.id)) 。一般来说,不要使用字符串格式在 SQL 查询中设置值,这样容易出错并且很危险。
    猜你喜欢
    • 2017-08-08
    • 2011-09-14
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    • 2013-08-21
    • 2013-12-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多