3 回答

TA貢獻(xiàn)1775條經(jīng)驗(yàn) 獲得超11個(gè)贊
這是我做樂(lè)觀鎖在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中的方法實(shí)現(xiàn)。
我做出以下假設(shè):
filter()。update()將導(dǎo)致單個(gè)數(shù)據(jù)庫(kù)查詢(xún),因?yàn)閒ilter是惰性的
數(shù)據(jù)庫(kù)查詢(xún)是原子的
這些假設(shè)足以確保之前沒(méi)有其他人更新過(guò)該條目。如果以這種方式更新了多行,則應(yīng)使用事務(wù)。
警告 Django Doc:
請(qǐng)注意,update()方法直接轉(zhuǎn)換為SQL語(yǔ)句。這是直接更新的批量操作。它不會(huì)對(duì)你的模型運(yùn)行任何save()方法,或發(fā)出pre_save或post_save信號(hào)

TA貢獻(xiàn)1777條經(jīng)驗(yàn) 獲得超3個(gè)贊
這個(gè)問(wèn)題有點(diǎn)老了,我的回答有點(diǎn)晚了,但是在我理解之后,在Django 1.4中使用以下命令解決了這個(gè)問(wèn)題:
select_for_update(nowait=True)
看文檔
返回一個(gè)查詢(xún)集,該查詢(xún)集將鎖定行直到事務(wù)結(jié)束,從而在支持的數(shù)據(jù)庫(kù)上生成SELECT ... FOR UPDATE SQL語(yǔ)句。
通常,如果另一個(gè)事務(wù)已經(jīng)獲取了所選行之一的鎖,則查詢(xún)將阻塞,直到釋放該鎖為止。如果這不是您想要的行為,請(qǐng)調(diào)用select_for_update(nowait = True)。這將使呼叫成為非阻塞。如果另一個(gè)事務(wù)已經(jīng)獲取了沖突的鎖,則在評(píng)估查詢(xún)集時(shí)將引發(fā)DatabaseError。
當(dāng)然,這僅在后端支持“選擇更新”功能時(shí)才起作用,例如sqlite不支持。不幸的是:nowait=TrueMySql不支持:您必須在其中使用:nowait=False,它只會(huì)在釋放鎖之前阻塞。

TA貢獻(xiàn)1824條經(jīng)驗(yàn) 獲得超8個(gè)贊
實(shí)際上,事務(wù)在這里無(wú)濟(jì)于事...除非您希望使事務(wù)運(yùn)行在多個(gè)HTTP請(qǐng)求上(您可能不希望這樣做)。
在這些情況下,我們通常使用的是“樂(lè)觀鎖定”。據(jù)我所知,Django ORM不支持該功能。但是,已經(jīng)有一些關(guān)于添加此功能的討論。
所以你自己一個(gè)人?;旧希鷳?yīng)該做的是在模型中添加一個(gè)“版本”字段,并將其作為隱藏字段傳遞給用戶(hù)。更新的正常周期為:
讀取數(shù)據(jù)并將其顯示給用戶(hù)
用戶(hù)修改數(shù)據(jù)
用戶(hù)發(fā)布數(shù)據(jù)
該應(yīng)用程序?qū)⑵浔4婊財(cái)?shù)據(jù)庫(kù)中。
為了實(shí)現(xiàn)樂(lè)觀鎖定,在保存數(shù)據(jù)時(shí),您需要檢查從用戶(hù)那里獲得的版本是否與數(shù)據(jù)庫(kù)中的版本相同,然后更新數(shù)據(jù)庫(kù)并遞增版本。如果不是,則表示自加載數(shù)據(jù)以來(lái)發(fā)生了更改。
您可以通過(guò)單個(gè)SQL調(diào)用來(lái)實(shí)現(xiàn),例如:
UPDATE ... WHERE version = 'version_from_user';
僅當(dāng)版本相同時(shí),此調(diào)用才會(huì)更新數(shù)據(jù)庫(kù)。
- 3 回答
- 0 關(guān)注
- 1023 瀏覽
添加回答
舉報(bào)