【问题标题】:Django: How to lock rows for reading?Django:如何锁定行以供阅读?
【发布时间】:2018-07-20 00:26:37
【问题描述】:

我的表包含并发工作人员的“任务”。所以工人应该能够从表中“获取”任务,这意味着原子地检查任务是否存在,如果存在,删除它。其他工作人员应该被锁定,直到这个原子过程完成。如何在 Django 中执行这种锁定?

我正在使用如下代码,但是行没有锁定读取,两个并发工作者都进入事务,找到相同的任务,一个成功获得它,但第二个得到OperationalError('database is locked',)

使用SQLite

class Task(models.Model):

    @staticmethod
    def get():
        with transaction.atomic():
            task = Task.objects.select_for_update().filter(...).first()
            if task:
                task.delete()
                return task

        return None

【问题讨论】:

  • 锁错误的worker应该一直尝试直到拥有事务锁的worker完成。最终它会获得写锁并做它的事情。

标签: django database sqlite locking


【解决方案1】:

所以我明白了使用生产就绪数据库的目的,但是要使用 SQLite,使用 Redis.lock() 很容易:

class Task(models.Model):

    @staticmethod
    def get():

        from redis import StrictRedis
        with StrictRedis().lock("some_lock_id"):

            task = Task.objects.filter(...).first()
            if task:
                task.delete()
                return task

        return None

【讨论】:

    【解决方案2】:

    SQLite 中没有行级锁支持,部分原因是它是基于文件的数据库:

    https://www.sqlite.org/atomiccommit.html

    读取数据库文件的第一步是获取数据库文件的共享锁。 “共享”锁允许两个或多个数据库连接同时从数据库文件中读取。但是共享锁会阻止另一个数据库连接在我们读取数据库文件时写入它。

    最好的办法是切换到生产质量数据库,例如PostgreSQL

    13.3.2.行级锁

    除了表级锁,还有行级锁,下面列出了它们被PostgreSQL自动使用的上下文。

    【讨论】:

    • 好的,谢谢。所以用sqlite也不能锁定整个数据库来读取?
    • 共享锁只阻止另一个连接写入,而不是读取。你应该仍然可以从中选择。
    猜你喜欢
    • 1970-01-01
    • 2012-04-22
    • 2023-03-19
    • 1970-01-01
    • 2012-07-29
    • 2020-06-17
    • 1970-01-01
    • 1970-01-01
    • 2021-11-07
    相关资源
    最近更新 更多