【问题标题】:sqlite database table is locked on testssqlite 数据库表在测试中被锁定
【发布时间】:2018-01-20 05:41:59
【问题描述】:

我正在尝试将应用程序从 django 1.11.1 迁移到 django 2.0.1 测试设置为在内存数据库中使用 sqlite 运行。但是每个测试都失败了,因为每个表都有sqlite3.OperationalError: database table is locked。我怎样才能知道它为什么被锁定?增加超时设置没有帮助。

我正在使用LiveServerTestCase,所以我认为测试必须在与内存数据库不同的线程中运行,并且由于某种原因它没有被共享。

【问题讨论】:

  • 您的 sqlite3 数据库是否有可能在某些 IDE 中打开?
  • 没有。在 wercker 上运行的测试得到相同的错误。
  • 您是否在并行运行测试?
  • 我如何确定我不是?即使这样,至少有一个测试应该通过,还是失败并显示不同的消息?
  • 如何运行测试?你的 TestRunner 是什么?

标签: django database sqlite testing


【解决方案1】:

我也打过这个。 LiveServerTestCase 是多线程的,因为 this got merged

当我的被测应用发出多个请求时,这对我来说是个问题。然后,我推测,LiveServer 会产生线程来处理这些请求。然后这些请求会导致写入 SQLite 数据库。这反过来又不喜欢多个写入线程。

有趣的是,runserver 知道 --nothreading。但是测试服务器似乎缺少这样的选项。

下面的sn-p给我带来了一个单线程的测试服务器:

class LiveServerSingleThread(LiveServerThread):
    """Runs a single threaded server rather than multi threaded. Reverts https://github.com/django/django/pull/7832"""

    def _create_server(self):

        """
        the keep-alive fixes introduced in Django 2.1.4 (934acf1126995f6e6ccba5947ec8f7561633c27f)
        cause problems when serving the static files in a stream.
        We disable the helper handle method that calls handle_one_request multiple times.
        """
        QuietWSGIRequestHandler.handle = QuietWSGIRequestHandler.handle_one_request

        return WSGIServer((self.host, self.port), QuietWSGIRequestHandler, allow_reuse_address=False)


class LiveServerSingleThreadedTestCase(LiveServerTestCase):
    "A thin sub-class which only sets the single-threaded server as a class"
    server_thread_class = LiveServerSingleThread

然后,从LiveServerSingleThreadedTestCase 而不是LiveServerTestCase 派生您的测试类。

【讨论】:

  • 如果您需要它:from django.test.testcases import LiveServerThread, QuietWSGIRequestHandlerfrom django.core.servers.basehttp import WSGIServer
  • 这只会导致测试超时而不是引发死锁错误。
  • 对我来说,这会让每个请求都永远挂起
  • 是的。发生了变化。但我已经更新了 sn-p 以反映我们用来使其工作的方法。
【解决方案2】:

这是由this django 错误引起的。

【讨论】:

    【解决方案3】:

    在测试期间使用基于文件的数据库可修复“表已锁定”错误。要让 Django 使用基于文件的数据库,请将其文件名指定为测试数据库名称:

    DATABASES = {
        'default': {
            ...
            'TEST': {
                'NAME': os.path.join(BASE_DIR, 'db.sqlite3.test'),
           },
        }
    }
    

    我想在内存数据库的情况下忽略超时设置,请参阅comment for additional info

    【讨论】:

    • 这抵消了使用内存中 Sqlite 数据库的大部分好处。使用文件会大大降低数据库速度。
    猜你喜欢
    • 1970-01-01
    • 2019-10-07
    • 1970-01-01
    • 2011-08-05
    • 2011-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多