在Python中为MySQL转义Unicode字符串(避免exceptions.UnicodeEncodeError)
我正在使用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 个回答
你可以试试:
newrecordslist[record].decode("utf-8")
Glyph说得对,关于这个可以参考 http://www.python.org/dev/peps/pep-0249/。
不要像这样格式化字符串。这是一个巨大的安全漏洞。你自己很难正确处理引号,所以不要尝试。
使用'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字符串中。