亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Django:如何防止數據庫條目的并發修改

Django:如何防止數據庫條目的并發修改

月關寶盒 2019-11-06 10:37:20
是否存在防止兩個或多個用戶同時修改同一數據庫條目的方法?向用戶顯示執行第二次提交/保存操作的錯誤消息是可以接受的,但是數據不應被靜默覆蓋。我認為鎖定項目不是一個選項,用戶可以使用“后退”按鈕或干脆關閉其瀏覽器,留下了鎖,直到永遠。
查看完整描述

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信號


查看完整回答
反對 回復 2019-11-06
?
慕森王

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,它只會在釋放鎖之前阻塞。


查看完整回答
反對 回復 2019-11-06
?
有只小跳蛙

TA貢獻1824條經驗 獲得超8個贊

實際上,事務在這里無濟于事...除非您希望使事務運行在多個HTTP請求上(您可能不希望這樣做)。


在這些情況下,我們通常使用的是“樂觀鎖定”。據我所知,Django ORM不支持該功能。但是,已經有一些關于添加此功能的討論。


所以你自己一個人。基本上,您應該做的是在模型中添加一個“版本”字段,并將其作為隱藏字段傳遞給用戶。更新的正常周期為:


讀取數據并將其顯示給用戶

用戶修改數據

用戶發布數據

該應用程序將其保存回數據庫中。

為了實現樂觀鎖定,在保存數據時,您需要檢查從用戶那里獲得的版本是否與數據庫中的版本相同,然后更新數據庫并遞增版本。如果不是,則表示自加載數據以來發生了更改。


您可以通過單個SQL調用來實現,例如:


UPDATE ... WHERE version = 'version_from_user';

僅當版本相同時,此調用才會更新數據庫。


查看完整回答
反對 回復 2019-11-06
  • 3 回答
  • 0 關注
  • 1015 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號