如何让Django管理命令不打开事务?

7 投票
1 回答
2223 浏览
提问于 2025-04-17 19:32

我正在写一个管理命令,想要改变默认的隔离级别。Django和我的数据库默认是“已提交读取”(READ COMMITTED),但我只希望这个特定的管理命令使用“未提交读取”(READ UNCOMMITTED)。

当我运行:

./manage.py my_command

我注意到,Django 默认会以默认的隔离级别打开一个事务,即使你的命令不需要任何数据库连接:

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    help = "Updates assortment data by refreshing the mviews"

    def handle(self, *args, **options):
        print "fdkgjldfkjgdlkfjgklj"

这种行为不符合我的需求,所以我想知道有没有办法:

  • 写一个管理命令,让Django完全不接触数据库,所有的事务控制都由我手动管理?

  • 写一个管理命令,只为这个命令定义事务特性?

谢谢

1 个回答

6

我在Facebook上看到你的帖子,觉得我可以帮上忙 :-)

你可以在你的 settings.py 文件中设置数据库连接为“读取未提交”,具体方法如下:

DATABASES: {
    'default': {...}
    'uncommitted_db': {
        'ENGINE': ...
        'NAME': ...
        'USER': '...',
        'PASSWORD': '...',
        'HOST': '...', 
        'OPTIONS': {
            'init_command': 'SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED'  #MySQL
            'init_command': 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED' #Postgres
        }
    }
}

设置好之后,你就可以用Django的普通多数据库语法来访问你的非事务性数据库连接了:

Model.objects.using('uncommitted_db').all()

当然,你可能不希望在整个应用程序中都能全局访问这个非事务性数据库连接,所以理想情况下,你希望它只在执行这个管理命令时可用。不幸的是,管理命令并不是这样工作的:一旦你调用了 Command 类中的 handle 方法,你的 settings.py 文件就已经被解析,数据库连接也已经创建好了。如果你能找到一种方法,在运行时用一组新的数据库设置重新初始化Django,或者根据启动条件在你的 settings.py 中进行逻辑分割,比如这样:

import sys
if 'some_management_cmd' in sys.argv: 
    DATABASES['default']['OPTIONS']['init_command'] = 'SET TRANSACTION...'

这样做是可行的,但实在是太麻烦了!

撰写回答