在Python中为MySQL转义Unicode字符串(避免exceptions.UnicodeEncodeError)

4 投票
2 回答
4929 浏览
提问于 2025-04-16 05:39

我正在使用Twisted库在Python中异步访问我们的数据库。我的代码大致是这样的:

from twisted.enterprise import adbapi
from MySQLdb import _mysql as mysql

...

txn.execute("""
    INSERT INTO users_accounts_data_snapshots (accountid, programid, fieldid, value, timestamp, jobid)
    VALUES ('%s', '%s', '%s', '%s', '%s', '%s')
""" % (accountid, programid, record, mysql.escape_string(newrecordslist[record]), ended, jobid))

这段代码之前一直运行得很好,直到我遇到了这个字符:®,这导致程序抛出了一个异常:`exceptions.UnicodeEncodeError: 'ascii' codec can't encode character u'\xae' in position 7: ordinal not in range(128)

不过,如果我不使用MySQLdb_mysql.escape_string(),当输入包含引号等字符时,就会出现数据库错误(这当然是正常的)。这个异常发生在访问数据库之前,所以数据库的字符集似乎并不重要。

有没有什么好的方法可以处理这些内容,而不会因为unicode字符而抛出异常?理想的解决方案是我可以将unicode字符直接传给MySQL,而不会影响查询;不过,去掉字符串中的unicode字符、用问号替换它们、或者其他任何能避免崩溃的方法也是可以接受的。

2 个回答

2

你可以试试:

newrecordslist[record].decode("utf-8")

Glyph说得对,关于这个可以参考 http://www.python.org/dev/peps/pep-0249/

11

不要像这样格式化字符串。这是一个巨大的安全漏洞。你自己很难正确处理引号,所以不要尝试。

使用'execute'的第二个参数。简单来说,不要这样写 txn.execute("... %s, %s ..." % ("xxx", "yyy")),而是这样写 txn.execute("... %s, %s ...", ("xxx", "yyy"))。注意这里用的是逗号,而不是百分号。在其他数据库或者使用不同的数据库绑定时,你可能会用不同的符号代替"%s",比如 ? 或者 :1, :2, :3,或者 :foo:, :bar:, :baz:,但思路是一样的。如果你对其他选项感兴趣,可以查看DB-API 2.0文档中的paramstyle

我之前写过关于这个的文章。那篇文章的讨论可能会对你特别有帮助。

我还想强调这才是唯一正确的方法。你可能见过MySQL的文档提到过用不同方式处理字符串引号。你可能在PHP中写过应用程序,但PHP没有合适的方法来传递数据库参数。我可以保证,所有这些信息来源都是错误的,会导致严重的安全问题:不要把参数直接插入到你的SQL字符串中。

撰写回答