2

我正在查看代码库,特别是数据库连接部分,并遇到了这个问题。

首先,使用以下语句获取数据库的游标:

from django.db import connection, transaction
cursor = connection.cursor()

connection 是一个模块属性,因此在线程模型中,所有线程都将共享该变量。听起来有点奇怪。进一步深入, cursor() 方法属于 django.db.backends.BaseDatabaseWrapper ,如下所示:

def cursor(self):
        self.validate_thread_sharing()
        if (self.use_debug_cursor or
            (self.use_debug_cursor is None and settings.DEBUG)):
            cursor = self.make_debug_cursor(self._cursor())
        else:
            cursor = util.CursorWrapper(self._cursor(), self)
    return cursor

关键是调用 _cursor(),它为正在使用的任何数据库执行后端代码。对于 MySQL,它在 django.db.backends.mysql.DatabaseWrapper 上执行 _cursor() 方法,如下所示:

def _cursor(self):
    new_connection = False
    if not self._valid_connection():
        new_connection = True
        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'] = 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'])
        self.connection = Database.connect(**kwargs)
        self.connection.encoders[SafeUnicode] = self.connection.encoders[unicode]
        self.connection.encoders[SafeString] = self.connection.encoders[str]
        connection_created.send(sender=self.__class__, connection=self)
    cursor = self.connection.cursor()
    if new_connection:
        # SQL_AUTO_IS_NULL in MySQL controls whether an AUTO_INCREMENT column
        # on a recently-inserted row will return when the field is tested for
        # NULL.  Disabling this value brings this aspect of MySQL in line with
        # SQL standards.
        cursor.execute('SET SQL_AUTO_IS_NULL = 0')
    return CursorWrapper(cursor)

所以不一定要创建一个新的游标。如果已调用 _cursor(),则将返回先前使用的游标。

在线程模型中,这意味着多个线程可能共享同一个数据库游标,这似乎是一个禁忌。

还有其他迹象表明 Django 中不允许使用线程。此模块级代码来自 django/db/ init .py,例如:

def close_connection(**kwargs):
    for conn in connections.all():
        conn.close()
signals.request_finished.connect(close_connection)

因此,如果任何请求完成,所有数据库连接都将关闭。如果有并发请求怎么办?

似乎有很多东西正在共享,这表明不允许使用线程。我在任何地方都没有看到同步代码。

谢谢!

4

0 回答 0