2016-09-13 160 views
0

更新: 我做了一些測試select_for_update。我正在使用django 1.8.12。我在不同的shell中運行以下函數,連接到我的本地mariadb(引擎是InnoDB)。似乎select_for_update鎖定其他行?不知道是否我做了正確的方法測試:django過濾器和更新

def with_sleep(resource): 
    try: 
     with transaction.atomic(): 
      resource = resourceA.objects.select_for_update().filter(A=resource).first() 
      print('before sleep') 
      time.sleep(10) 
      print('after sleep') 
      resource.available = False 
      resource.save() 
      return True 
    except: 
      handle_exception() 

def withouth_sleep(resource): 
    try: 
     with transaction.atomic(): 
      print('try') 
      resource = resourceA.objects.select_for_update().filter(A=resource).first() 
      print('get resource') 
      resource.available = False 
      print('save') 
      resource.save() 
      return True 
    except: 
      handle_exception() 

我首先調用with_sleep(resource1)功能和呼叫然後without_sleep(resource2)resource1resource2是我模型中的不同資源。從shell中,我看到第二個函數在try之後被阻止,直到第一個函數從睡眠中醒來。那是否意味着resource2的行也被鎖定?

這個問題聽起來很愚蠢。感謝您提供任何建議或對測試進行任何更改。

原始問題: 我有一個資源模型,用於檢查資源是否可用,並且它在兩臺服務器上運行多個芹菜工作器以每次檢索下一個可用資源。如果可用,請將其狀態更改爲不可用並分配給該任務。

例如:

Class resourceA(model.Model): 
    A = models.CharField(max_length=10) 
    available = models.BooleanField(default=True) 

每次,我只是想選擇下一個可用資源並分配給任務。 如果我做

resource = resourceA.objects.filter(available=True).first() 
if resource: 
    resource.available=False 
    resource.save() 

然後有機會的話,其他的工人可能會選擇相同的資源,並嘗試對其進行更新。

Django有select_for_update鎖定條目。但是,我不想鎖定和更新所有可用資源。

請建議是否有任何方法,以便我可以一次檢索和更新?

+0

你正在使用什麼數據庫? – Windsooon

+0

@Asion我正在使用sqlite進行測試,並將在生產中使用mysql。 – user6828492

回答

1

select_for_update將僅鎖定行,所以在您的查詢中使用first()將只有一行被鎖定。

因此 - 使用select_for_update

+0

感謝您的回答!我用select_for_update做了一些測試。似乎沒有按預期工作。請檢查更新。 – user6828492

+0

從我在更新中看到的內容中,可以霧化數據庫中的同一行'first()'。在這種情況下,這是預期的行爲。行被鎖定,直到被釋放。嘗試在'withouth_sleep'塊中用'last()'來做。如果它按預期工作(立即執行) - 這就是你想要的,只有你工作的行被鎖定。 –

+0

實際上,我只是爲了測試'select_for_update'而將2個不同的資源傳遞給更新中的那些函數。當調用'.filter()'時,他們實際上選擇了不同的行。我認爲通過使用'.first()'和'.last()',他們應該有相同的行爲,他們做到了。 – user6828492