Django:如何防止并发修改数据库条目
是否有办法防止两个或多个用户同时修改同一数据库条目 向执行第二次提交/保存操作的用户显示错误消息是可以接受的,但数据不应被静默覆盖Django:如何防止并发修改数据库条目,django,django-models,concurrency,transactions,atomic,Django,Django Models,Concurrency,Transactions,Atomic,是否有办法防止两个或多个用户同时修改同一数据库条目 向执行第二次提交/保存操作的用户显示错误消息是可以接受的,但数据不应被静默覆盖 我认为锁定条目不是一个选项,因为用户可能会使用“后退”按钮或简单地关闭浏览器,永远保持锁定。为了安全起见,数据库需要支持 如果字段为“自由格式”,例如文本等,并且您需要允许多个用户编辑相同的字段(您不能对数据拥有单用户所有权),则可以将原始数据存储在变量中。 当用户提交时,检查输入数据是否已从原始数据更改(如果未更改,则无需通过重写旧数据来打扰数据库), 如果原始数
我认为锁定条目不是一个选项,因为用户可能会使用“后退”按钮或简单地关闭浏览器,永远保持锁定。为了安全起见,数据库需要支持 如果字段为“自由格式”,例如文本等,并且您需要允许多个用户编辑相同的字段(您不能对数据拥有单用户所有权),则可以将原始数据存储在变量中。 当用户提交时,检查输入数据是否已从原始数据更改(如果未更改,则无需通过重写旧数据来打扰数据库), 如果原始数据与数据库中的当前数据相比是相同的,则可以保存;如果原始数据已更改,则可以向用户显示差异,并询问用户如何操作 如果字段是数字,例如帐户余额、商店中的项目数等,则如果计算原始值(用户开始填写表单时存储的)与新值之间的差值,则可以更自动地处理该字段。您可以启动事务,读取当前值并添加差值,然后结束事务。如果不能有负值,则应在结果为负值时中止事务,并告知用户
我不认识django,所以我不能给你这些密码 为了安全起见,数据库需要支持 如果字段为“自由格式”,例如文本等,并且您需要允许多个用户编辑相同的字段(您不能对数据拥有单用户所有权),则可以将原始数据存储在变量中。 当用户提交时,检查输入数据是否已从原始数据更改(如果未更改,则无需通过重写旧数据来打扰数据库), 如果原始数据与数据库中的当前数据相比是相同的,则可以保存;如果原始数据已更改,则可以向用户显示差异,并询问用户如何操作 如果字段是数字,例如帐户余额、商店中的项目数等,则如果计算原始值(用户开始填写表单时存储的)与新值之间的差值,则可以更自动地处理该字段。您可以启动事务,读取当前值并添加差值,然后结束事务。如果不能有负值,则应在结果为负值时中止事务,并告知用户
我不认识django,所以我不能给你这些密码 事实上,交易在这里帮不了你多少忙。。。除非您希望在多个HTTP请求上运行事务(您很可能不希望这样) 在这些情况下,我们通常使用的是“乐观锁定”。据我所知,Django ORM不支持这一点。但关于添加此功能,已经有一些讨论 所以你只能靠自己了。基本上,您应该做的是向模型中添加一个“版本”字段,并将其作为隐藏字段传递给用户。更新的正常周期为:
UPDATE ... WHERE version = 'version_from_user';
只有当版本仍然相同时,此调用才会更新数据库。实际上,事务在这里帮不了你多少忙。。。除非您希望在多个HTTP请求上运行事务(您很可能不希望这样) 在这些情况下,我们通常使用的是“乐观锁定”。据我所知,Django ORM不支持这一点。但关于添加此功能,已经有一些讨论 所以你只能靠自己了。基本上,您应该做的是向模型中添加一个“版本”字段,并将其作为隐藏字段传递给用户。更新的正常周期为:
UPDATE ... WHERE version = 'version_from_user';
只有版本仍然相同时,此调用才会更新数据库。另一个需要查找的是“原子”一词。原子操作意味着您的数据库更改要么成功,要么明显失败。快速搜索显示询问Django中的原子操作。另一个要查找的是“原子”一词。原子操作意味着您的数据库更改要么成功,要么明显失败。快速搜索显示询问Django中的原子操作。您可能至少应该使用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()
select_for_update(nowait=True)