def safe_update(request,model,id):
obj = model.objects.get(id)
if obj.locked:
raise SimultaneousUpdateError #Define this somewhere
else:
obj.lock()
return update_object(request,model,id)
# In models file
class SomeModel(models.Model):
locked = models.BooleanField(default = False)
def lock(self):
self.locked = True
super(models.Model,self).save()
def save(self):
# overriding save because you want to use generic views
# probably not the best idea to rework model code to accomodate view shortcuts
# but I like to give examples.
self.locked = False
# THIS CREATES A DIFFERENT CRITICAL REGION!
super(models.Model,self).save()
5条答案
按热度按时间ctrmrzij1#
select_for_update是获取对象锁的最简单的方法,前提是你的数据库支持它。根据Django文档,至少PostgreSQL、Oracle和MySQL支持它。
示例代码:
注意,您必须在事务中使用
select_for_update
,因此使用@transaction.atomic
装饰器。vojdkbi02#
因此,有很多方法可以实现你所要求的,但其中很多方法都不是独立于实现的:你可以使用锁或者rlock,但是它们实际上只能在100%线程化的服务器上工作,并且可能在fork/pre-fork实现中根本不起作用。
这或多或少意味着锁的实现将取决于您。
1.文件系统上的
.lock
文件1.模型类中的
locked
属性在这两种情况下,您都必须在更新时手动设置锁对象,并在删除时检查它。
这确实是一个笨拙的实现,您必须进行清理。您可能对创建了不同的关键区域感到不舒服,但是如果您使用数据库作为实现而不使实现复杂得多,我看不出您会做得更好。(一种选择是让锁完全独立于对象,然后在调用保存()方法后更新它们,但我不想编写这样的代码。)如果你真的想使用一个基于文件的锁定系统,那么它也能解决这个问题。如果你有数据库命中妄想症,那么它可能适合你。比如:
无论如何,也许有一些方法可以混合和匹配这些建议,以您的口味?
0x6upsns3#
因为你的范围被限制在删除,而不是更新,一个选择是重新考虑“删除”作为“取消发布”操作的想法。
这样,无论何时提交编辑,所有用户都可以看到它......但其他用户仍然可以自由删除项目。这种技术的一个优点是,您不必使用任何额外的逻辑来锁定项目并向用户呈现不同的UI。缺点是,在数据库表中使用了额外的空间,并且很少会出现已删除项目“神奇地”重新出现的情况。
(This这可能只是一个起点,如果你选择了这条路,你可能会想根据你的用例对这个想法做一个变化。)
soat7uwm4#
我建议使用一个简单的读写锁,因为您不希望阻止用户并发访问对象(仅阻止编辑)。
一般的方法是创建一个函数来维护活动的读取者的计数。当你需要写入这个对象时,你可以创建另一个函数来阻止新的读取者获得访问(想想维护页面),并且可能重定向现有的读取者。一旦没有更多的读取者留下,你就可以完成你的写入,然后解锁对象。
unguejic5#
首先,您需要知道有两种锁定机制:乐观锁和悲观锁。here解释了它们的区别。据我所知,Django没有实现悲观锁的包。对于乐观锁,最完整的库是django-concurrency。