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

Django 1.11.1迁移至2.0.1后SQLite内存库测试表锁定排查求助

排查与解决 SQLite 表锁定问题(LiveServerTestCase + Django 2.0)

我之前迁移 Django 版本时也碰到过几乎一模一样的坑!先给你戳破核心问题:SQLite 的内存数据库(:memory:)是每个数据库连接私有的。LiveServerTestCase 会启动一个独立的 HTTP 服务线程,这个线程会新建一个数据库连接——它访问的内存库和你测试主线程里的完全不是同一个!这就导致两种混乱情况:要么服务线程找不到主线程建好的表,尝试重复创建时触发冲突;要么双方各自操作“私有库”时,因 SQLite 的单写特性触发锁错误。

下面给你一步步排查和解决的实用思路:

1. 先验证是不是内存库的共享问题

先把测试用的数据库临时改成磁盘文件试试,在测试环境的 settings.py 里修改:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 'test_temp_db.sqlite3',  # 换成磁盘文件
    }
}

如果测试能正常跑,那百分之百是内存库的多线程共享问题——磁盘文件是所有连接共享的,不会出现“各玩各的库”的情况。

2. 让内存库支持多线程共享(不想用磁盘文件的话)

SQLite 其实提供了共享内存库的方案,用 file::memory:?cache=shared 作为数据库名称,它会把内存库作为共享缓存,让所有连接都能访问同一个实例。修改测试配置:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 'file::memory:?cache=shared',
    }
}

注意:这个特性需要 SQLite 3.7.13 及以上版本支持,先跑 sqlite3 --version 确认你的版本达标。

3. 检查 LiveServerTestCase 的线程与迁移逻辑

Django 2.0 对比 1.11,LiveServerTestCase 的默认行为有调整,比如自动迁移的时机可能和主线程的数据库初始化冲突。你可以手动控制迁移时机:

class MyTestClass(LiveServerTestCase):
    @classmethod
    def setUpClass(cls):
        # 禁用自动迁移,让主线程先建好表再启动服务器
        cls.migrate = False
        super().setUpClass()
        # 手动执行迁移
        from django.core.management import call_command
        call_command('migrate')

这样能确保服务器线程启动时,数据库表已经完全就绪,避免冲突。

4. 排查未关闭的数据库连接

Django 2.0 对事务和连接的处理逻辑有变化,如果测试代码里手动打开了连接没关闭,或者事务没提交/回滚,很容易触发锁。可以在测试的清理步骤里强制关闭所有连接:

def tearDown(self):
    from django.db import connections
    for conn in connections.all():
        conn.close()
    super().tearDown()

5. 换用更轻量的测试类(如果场景允许)

如果你的测试不需要真的启动 HTTP 服务器,只是验证视图逻辑,换成 TransactionTestCase 甚至普通的 TestCase 会稳定很多——毕竟 LiveServerTestCase 因为多线程特性,本身就引入了额外的复杂度。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:44:39