Ber*_*Ber 77 django concurrency transactions atomic django-models
如果有办法防止两个或多个用户同时修改同一数据库条目?
向执行第二次提交/保存操作的用户显示错误消息是可以接受的,但不应以静默方式覆盖数据.
我认为锁定条目不是一个选项,因为用户可能会使用"后退"按钮或只是关闭他的浏览器,永远保持锁定.
And*_*avu 47
这就是我在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()
Run Code Online (Sandbox Code Playgroud)
上面列出的代码可以作为Custom Manager中的方法实现.
我做了以下假设:
这些假设足以确保之前没有其他人更新过该条目.如果以这种方式更新多行,则应使用事务.
警告 Django Doc:
请注意,update()方法直接转换为SQL语句.这是直接更新的批量操作.它不会在模型上运行任何save()方法,也不会发出pre_save或post_save信号
giZ*_*Zm0 36
这个问题有点陈旧,我的回答有点晚了,但据我所知,这已经在Django 1.4中修复了:
select_for_update(nowait=True)
Run Code Online (Sandbox Code Playgroud)
看文档
返回一个查询集,该查询集将锁定行直到事务结束,在支持的数据库上生成SELECT ... FOR UPDATE SQL语句.
通常,如果另一个事务已经对其中一个选定行获取了锁定,则查询将阻塞,直到锁定被释放.如果这不是您想要的行为,请调用select_for_update(nowait = True).这将使呼叫无阻塞.如果另一个事务已经获取了冲突锁,则在评估查询集时将引发DatabaseError.
当然,这仅在后端支持"select for update"功能时才有效,例如sqlite不支持.不幸的是:nowait=True
MySql不支持,你必须使用:nowait=False
,它只会在锁被释放之前阻塞.
Gui*_*ume 28
实际上,事务在这里对你没什么帮助...除非你想让事务在多个HTTP请求上运行(你很可能不想要).
我们在这些情况下通常使用的是"乐观锁定".据我所知,Django ORM不支持这一点.但是有一些关于添加此功能的讨论.
所以你是独立的.基本上,您应该做的是在模型中添加"版本"字段,并将其作为隐藏字段传递给用户.更新的正常周期是:
要实现乐观锁定,在保存数据时,检查从用户获得的版本是否与数据库中的版本相同,然后更新数据库并增加版本.如果不是,则表示自加载数据后发生了更改.
您可以通过单个SQL调用执行此操作,例如:
UPDATE ... WHERE version = 'version_from_user';
Run Code Online (Sandbox Code Playgroud)
仅当版本仍然相同时,此调用才会更新数据库.
kra*_*etz 13
Django 1.11有三个方便的选项来处理这种情况,具体取决于您的业务逻辑要求:
Something.objects.select_for_update()
将阻止,直到模型变为空闲Something.objects.select_for_update(nowait=True)
并捕获DatabaseError
模型当前是否已锁定以进行更新Something.objects.select_for_update(skip_locked=True)
不会返回当前锁定的对象在我的应用程序中,它在各种模型上同时具有交互式和批处理工作流程,我找到了这三个选项来解决大多数并发处理方案.
"等待" select_for_update
在顺序批处理过程中非常方便 - 我希望它们都能执行,但让他们花时间.在nowait
使用时用户要修改当前锁定用于更新的对象-我会告诉他们这是一个在这一刻被修改.
该skip_locked
用户何时可以触发对象的重新扫描是另一种类型的更新,有用的-我不关心谁触发它,只要它的触发,所以skip_locked
让我静静地跳过复制触发器.
Ste*_*aug -3
为了安全起见,数据库需要支持事务。
如果字段是“自由格式”,例如文本等,并且您需要允许多个用户能够编辑相同的字段(您不能拥有数据的单个用户所有权),您可以将原始数据存储在多变的。当用户提交时,检查输入数据与原始数据相比是否发生变化(如果没有,则无需通过重写旧数据来打扰数据库),原始数据与数据库中当前数据是否相同您可以保存,如果它发生了变化,您可以向用户展示差异并询问用户该怎么做。
如果字段是数字,例如帐户余额、商店中的商品数量等,如果您计算原始值(在用户开始填写表单时存储)和新值之间的差值,则可以更自动地处理它启动事务读取当前值并添加差值,然后结束事务。如果不能有负值,则应在结果为负时中止事务,并告诉用户。
我不了解 django,所以我不能给你 cod3s..;)
归档时间: |
|
查看次数: |
40047 次 |
最近记录: |