You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决Django中SQLite同时运行管理命令与/admin的数据库锁问题

Django + SQLite 数据库锁定问题解决方案

问题概述

  • 运行长时间管理命令./manage.sh download_company_data更新数据库时,Admin界面创建用户立即触发「数据库已锁定」错误
  • 已设置数据库timeout为20000,但未生效
  • 管理命令中单个update_or_create操作快速且不涉及User表,已添加重试逻辑、调用connections.close_all()并休眠1秒

解决办法

1. 修正SQLite超时配置的单位错误

SQLite的timeout参数单位是秒,而非毫秒。你当前设置的20000相当于5个多小时,可能导致配置解析异常无法生效。将超时调整为合理值(如20秒):

DATABASES = {                                                                              
    'default': {                                                                           
        'ENGINE': 'django.db.backends.sqlite3',                                             
        'NAME': BASE_DIR / 'db.sqlite3',                                                    
        'OPTIONS': { 
            'timeout': 20,  # 等待20秒再抛出锁定错误
        },                                                                                    
    }                                                                                       
}   

2. 开启SQLite WAL模式提升并发能力

SQLite默认的DELETE日志模式下,写操作会独占整个数据库锁。开启Write-Ahead Logging(WAL)模式后,可支持多读单写的并发操作,大幅减少锁冲突概率:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
        'OPTIONS': {
            'timeout': 20,
            'init_command': 'PRAGMA journal_mode=WAL;'  # 启用WAL模式
        },
    }
}

注意:开启WAL后,需重启runserver和管理命令进程确保所有连接生效。

3. 确保管理命令的事务及时提交

Django默认会为ORM操作开启事务,若事务未及时提交,会持续持有数据库锁。用transaction.atomic()包裹单个更新操作,确保事务完成后立即释放锁:

from django.db import transaction

for line in c:                                                                 
    line = preprocess(line, prefix)                                            
    search = { unique: line[unique] }
    for i in range(10):                                                        
        try:                                                                   
            with transaction.atomic():  # 原子操作确保事务及时提交
                Model.objects.update_or_create(**search, defaults=line)           
            break                                                              
        except OperationalError as e:                                          
            info('Operational error. Delayed retry...')                        
            sleep(0.02)                                                        
    connections.close_all()                                                    
    sleep(1)                                                                   

4. 给Admin用户添加操作重试逻辑

即使优化了后端,偶尔的锁冲突仍可能发生。自定义Admin类,为用户创建操作添加重试机制:

from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from django.db import OperationalError
import time

class RetryEnabledUserAdmin(UserAdmin):
    def save_model(self, request, obj, form, change):
        max_retries = 3
        retry_delay = 0.5  # 每次重试间隔0.5秒
        for attempt in range(max_retries):
            try:
                super().save_model(request, obj, form, change)
                return
            except OperationalError as e:
                if "database is locked" in str(e).lower():
                    if attempt < max_retries - 1:
                        time.sleep(retry_delay)
                        continue
                # 非锁定错误或重试耗尽,抛出原异常
                raise

# 替换默认的User Admin
admin.site.unregister(User)
admin.site.register(User, RetryEnabledUserAdmin)

5. 优化管理命令的连接使用

无需每次循环都调用connections.close_all(),改为仅关闭当前默认连接,避免不必要的连接重建开销:

# 替换 connections.close_all() 为
connections['default'].close()

内容的提问来源于stack exchange,提问作者hdante

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 20:13:19