3 回答

TA貢獻1775條經驗 獲得超11個贊
這是我做樂觀鎖在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信號

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

TA貢獻1824條經驗 獲得超8個贊
實際上,事務在這里無濟于事...除非您希望使事務運行在多個HTTP請求上(您可能不希望這樣做)。
在這些情況下,我們通常使用的是“樂觀鎖定”。據我所知,Django ORM不支持該功能。但是,已經有一些關于添加此功能的討論。
所以你自己一個人。基本上,您應該做的是在模型中添加一個“版本”字段,并將其作為隱藏字段傳遞給用戶。更新的正常周期為:
讀取數據并將其顯示給用戶
用戶修改數據
用戶發布數據
該應用程序將其保存回數據庫中。
為了實現樂觀鎖定,在保存數據時,您需要檢查從用戶那里獲得的版本是否與數據庫中的版本相同,然后更新數據庫并遞增版本。如果不是,則表示自加載數據以來發生了更改。
您可以通過單個SQL調用來實現,例如:
UPDATE ... WHERE version = 'version_from_user';
僅當版本相同時,此調用才會更新數據庫。
- 3 回答
- 0 關注
- 1015 瀏覽
添加回答
舉報