我试图为计数器实现(我认为是)一个非常简单的数据模型:

class VisitorDayTypeCounter(models.Model):
    visitType = models.CharField(max_length=60)
    visitDate = models.DateField('Visit Date')
    counter = models.IntegerField()

当有人通过时,它将查找与visitType和visitDate匹配的行;如果该行不存在,则将创建计数器=0.

然后我们增加计数器并保存.

我担心的是,这个过程完全是一场比赛.两个请求可以同时判断实体是否在那里,并且两个请求都可以创建它.在读取计数器和保存结果之间,另一个请求可能会通过并递增计数器(导致计数丢失).

到目前为止,无论是在Django文档中还是在教程中,我都没有找到解决这个问题的好方法(事实上,教程的投票部分似乎有一个种族条件).

我怎么才能安全地做这件事呢?

推荐答案

这有点像黑客行为.原始SQL将降低代码的可移植性,但它将消除计数器增量上的争用条件.从理论上讲,这应该会在您执行任何查询时递增计数器.我还没有测试过这一点,所以您应该确保在查询中正确插入列表.

class VisitorDayTypeCounterManager(models.Manager):
    def get_query_set(self):
        qs = super(VisitorDayTypeCounterManager, self).get_query_set()

        from django.db import connection
        cursor = connection.cursor()

        pk_list = qs.values_list('id', flat=True)
        cursor.execute('UPDATE table_name SET counter = counter + 1 WHERE id IN %s', [pk_list])

        return qs

class VisitorDayTypeCounter(models.Model):
    ...

    objects = VisitorDayTypeCounterManager()

Database相关问答推荐

如何将使用模块创建的 Redis RDB 文件迁移到没有该模块的部署? (RedisStack 版本 7.2+ 中不再包含 RedisGraph)

我们可以出于不同目的在同一 postgres 数据库上同时进行物理和逻辑复制吗?

使用 golan 查询 mongodb 中的集合并返回 id 作为字符串

utf-8 与 latin1

mysql数据库自动分区

如何在 sql server 2005 中获取到数据库的详细连接列表?

Select 正确的数据库:MySQL 与Everything 其它数据库

管理数据库中的产品计数

MySQL 慢查询日志(log) - 慢有多慢?

JOIN 三张表

如何允许多个用户同时连接到我的 H2 数据库?

我可以在 mysql 中的 select 语句上启动触发器吗?

B+ 树相对于 BST 的优势?

连接字符串中超时

Redis:数据库大小与内存的比率?

寻找示例数据库设计的好方法

Fluent NHibernate 的类映射生成器

For循环或数据库调用哪个更好?

多币种 - 存储什么以及何时转换?

使用 Django 的复合/复合主/唯一键