前两天在家研究了下pypy,顺便也搭建了一个基于pypy的virtualenv环境: 创建基于pypy的virtualenv虚拟环境 ,在上篇文章最后说到在用django处理mysql数据库的时候会出现这个错误,然后崩溃:Segmentation fault (core dumped)。经过这两天使用pdb进行一步步debug,终于发现问题所在了。
从一个 python manage.py sql blog
开始,阅读了大部分的 django.db.backends.mysql
的代码,稍带着也看了MySQLdb库的一些代码,终于最后找到了问题所在。
在这个过程中,不断的对比Django中的cursor和正常情况下直接用MySQL代码创建的cursor,发现没有太多的区别,Django中的cursor其实是对MySQLdb创建出来的cursor的包装—— CursorWrapper
和 CursorDebugWrapper
(位于: django.db.backends.util
) ,其中后面这个CursorDebugWrapper和django_debug_toolbar有很重要的关系,这里面计算了每个连接的执行SQL语句以及每个语句的执行时间。而其他的cursor的操作没有什么特别的地方。
有逻辑的推敲代码还是很重要的,通过短路法不断的尝试,最后终于定位到了是Django在创建一个connection时发生的错误。查错的方法很简单,在pdb下,在Django创建完成一个connection之后,手动创建cursor,然后执行查询,发现直接抛错了。这说明这个connection创建的有问题。(文件位于: django.db.backends.mysql.base
中)
看一下这个connection的创建过程:
.. code::
# ....省略代码
kwargs = {
'conv': django_conversions,
#'charset': 'utf8',
#'use_unicode': True,
}
settings_dict = self.settings_dict
if settings_dict['USER']:
kwargs['user'] = settings_dict['USER']
if settings_dict['NAME']:
kwargs['db'] = settings_dict['NAME']
if settings_dict['PASSWORD']:
kwargs['passwd'] = force_str(settings_dict['PASSWORD'])
if settings_dict['HOST'].startswith('/'):
kwargs['unix_socket'] = settings_dict['HOST']
elif settings_dict['HOST']:
kwargs['host'] = settings_dict['HOST']
if settings_dict['PORT']:
kwargs['port'] = int(settings_dict['PORT'])
# We need the number of potentially affected rows after an
# "UPDATE", not the number of changed rows.
kwargs['client_flag'] = CLIENT.FOUND_ROWS
kwargs.update(settings_dict['OPTIONS'])
t_kwargs = {}
import pdb;pdb.set_trace()
#self.connection = Database.connect(db='django5',host='127.0.0.1',user='root',passwd='root')
self.connection = Database.connect(**kwargs)
# ... 省略代码
尝试后发现去掉创建链接时 charset和use_unicode的参数创建就能成功。
到此为止问题已经找出来了。至于这俩参数的具体用处,下回再说。
最后补充一句,Django没必要同时设置charset和use_unicode,因为MySQLdb库中有对应的判定:
.. code:: python
charset = kwargs2.pop('charset', '')
if charset:
use_unicode = True
else:
use_unicode = False
当然,除非你设置charset后需要设置use_unicode为false:
.. code:: python
use_unicode = kwargs2.pop('use_unicode', use_unicode)
- from the5fire.com微信公众号:Python程序员杂谈