我知道在网上的一些地方已经谈过这个问题,但是我想不出答案,所以我想问一下。
我有以下python代码调用存储过程需要一个整数,但是我给它一个非ascii£符号u'\xa3'
,这使得它'unicode its pants'!
# -*- coding: utf-8 -*-
import MySQLdb
import config.default as cfg
conn = MySQLdb.connect(
host=cfg.db_host,
user=cfg.db_user,
passwd=cfg.db_pass,
db=cfg.db_name,
use_unicode=True
)
curs = conn.cursor(MySQLdb.cursors.DictCursor)
try:
curs.callproc('get_user_by_id', [u'\xa3'])
curs.nextset()
except MySQLdb.Warning, e:
print e.message
curs.close()
conn.close()
以上将导致以下错误,因为存储过程需要int
,因此生成警告,该数据库以unicode形式从数据库返回:
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa3' in position 26: ordinal not in range(128)
如果我将use_unicode
设置为默认值False
,那么我会收到警告:
Warning: Incorrect integer value: '£' for column 'p_user_id' at row 1
curs.nextset()
你们中的大多数人可能都知道python的unicode异常问题有点烦人(至少对我而且可能是非ascii语言ppl)
我找到了解决这个问题的几种方法:
1)覆盖_warning_check
中的MySQLdb.BaseCursor
功能并注释掉warn(w[-1], self.Warning, 3)
行(约117行)
- 不喜欢它,因为我希望看到警告
2)导入警告,然后添加warnings.filterwarnings('ignore', category=MySQLdb.Warning)
- 并未真正解决其他unicode警告的问题
3)将warnings.py
文件复制到我的应用程序的根目录,并更改formatwarning
函数以将消息格式化为unicode:
- 到目前为止似乎是最好的解决方案,但它是一个python核心文件!
def formatwarning(message, category, filename, lineno, line=None):
"""Function to format a warning the standard way."""
# s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
s = u"{}:{}: {}: {}\n".format(filename, lineno, category.__name__, message)
line = linecache.getline(filename, lineno) if line is None else line
if line:
line = line.strip()
s += " %s\n" % line
return s
当然有更好的方法吗?
答案 0 :(得分:0)
这似乎不再是一个问题,可能是由于模块或MySQL服务器的更新 - 运行MySQL 5.7.12。
我也从使用use_unicode
更改为设置字符集,因此我的连接字符串如下所示:
MySQLdb.connect(host=DB_HOST, user=DB_USER, passwd=DB_PSWD, db=DB_NAME, charset='UTF8', connect_timeout=5)
但是,我正在调整一个高吞吐量的应用程序,并发现通常Mysqldb模块在每次执行后请求警告,花费几毫秒。但是发现在执行之前向游标添加curs._defer_warnings = True
会阻止它,然后你可以使用self.warnings = curs._warnings
来获取警告的数量。
curs = self.conn.cursor(cursors.DictCursor)
curs._defer_warnings = True
try:
self.affected = curs.execute(sql, args)
self.warnings = curs._warnings
if sql.lower().startswith('insert'):
self.lastrowid = curs.lastrowid
elif sql.lower().startswith('select'):
self.data = curs.fetchall()
except MySQLError, e:
if e.args[0] == 1064:
raise Exception("MySQL Error [1064]: Error in SQL syntax")
else:
raise Exception("MySQL Error [{}]: {}".format(e.args[0], e.args[1]))
finally:
curs.close()