Django:如何防止数据库条目的并发修改

是否存在防止两个或多个用户同时修改同一数据库条目的方法?

向用户显示执行第二次提交/保存操作的错误消息是可以接受的,但是数据不应被静默覆盖。

我认为锁定项目不是一个选项,用户可以使用“后退”按钮或干脆关闭其浏览器,留下了锁,直到永远。


月关宝盒
浏览 972回答 3
3回答

繁星淼淼

这是我做乐观锁在Django:updated = Entry.objects.filter(Q(id=e.id) && Q(version=e.version))\          .update(updated_field=new_value, version=e.version+1)if not updated:    raise ConcurrentModificationException()上面列出的代码可以作为Custom Manager中的方法实现。我做出以下假设:filter()。update()将导致单个数据库查询,因为filter是惰性的数据库查询是原子的这些假设足以确保之前没有其他人更新过该条目。如果以这种方式更新了多行,则应使用事务。警告 Django Doc:请注意,update()方法直接转换为SQL语句。这是直接更新的批量操作。它不会对你的模型运行任何save()方法,或发出pre_save或post_save信号

慕森王

这个问题有点老了,我的回答有点晚了,但是在我理解之后,在Django 1.4中使用以下命令解决了这个问题:select_for_update(nowait=True)看文档返回一个查询集,该查询集将锁定行直到事务结束,从而在支持的数据库上生成SELECT ... FOR UPDATE SQL语句。通常,如果另一个事务已经获取了所选行之一的锁,则查询将阻塞,直到释放该锁为止。如果这不是您想要的行为,请调用select_for_update(nowait = True)。这将使呼叫成为非阻塞。如果另一个事务已经获取了冲突的锁,则在评估查询集时将引发DatabaseError。当然,这仅在后端支持“选择更新”功能时才起作用,例如sqlite不支持。不幸的是:nowait=TrueMySql不支持:您必须在其中使用:nowait=False,它只会在释放锁之前阻塞。

有只小跳蛙

实际上,事务在这里无济于事...除非您希望使事务运行在多个HTTP请求上(您可能不希望这样做)。在这些情况下,我们通常使用的是“乐观锁定”。据我所知,Django ORM不支持该功能。但是,已经有一些关于添加此功能的讨论。所以你自己一个人。基本上,您应该做的是在模型中添加一个“版本”字段,并将其作为隐藏字段传递给用户。更新的正常周期为:读取数据并将其显示给用户用户修改数据用户发布数据该应用程序将其保存回数据库中。为了实现乐观锁定,在保存数据时,您需要检查从用户那里获得的版本是否与数据库中的版本相同,然后更新数据库并递增版本。如果不是,则表示自加载数据以来发生了更改。您可以通过单个SQL调用来实现,例如:UPDATE ... WHERE version = 'version_from_user';仅当版本相同时,此调用才会更新数据库。
打开App,查看更多内容
随时随地看视频慕课网APP