爲避免競爭條件,我需要在查詢數據庫時使用select for update
功能,以便鎖定行直到事務結束。由於select_for_update查詢在Django 1.3中不存在,我通過使用通過執行原始sql查詢返回查詢集合的類方法來完成解決方法。選擇更新查詢:鎖定等待超時超出錯誤
#models.py
class AccountDetails(models.Model):
user = models.OneToOneField(User)
amount = models.IntegerField(max_length=15,null=True,blank=True)
@classmethod
def get_locked_for_update(cls,userid):
accounts = cls.objects.raw("SELECT * FROM b2b_accountdetails WHERE user_id ="+str(userid)+" FOR UPDATE")
return accounts[0]
這就是它在視圖中的用法。
account = AccountDetails.get_locked_for_update(userid)
account.amount = account.amount - fare
account.save()
在最後一行我得到這個錯誤: OperationalError: (1205, 'Lock wait timeout exceeded; try restarting transaction')
在dbshell,運行save()
行之後:
mysql> SHOW FULL PROCESSLIST;
+-----+------+-----------+-----------+---------+------+----------+-----------------------------------------------------------------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+-----+------+-----------+-----------+---------+------+----------+-------------------------- ---------------------------------------------------------------------------+
| 51 | root | localhost | dbname | Query | 0 | NULL | SHOW FULL PROCESSLIST |
| 767 | root | localhost | dbname | Sleep | 59 | | NULL |
| 768 | root | localhost | dbname | Query | 49 | Updating | UPDATE `b2b_accountdetails` SET `user_id` = 1, `amount` = 68906 WHERE `appname_accountdetails`.`id` = 1 |
+-----+------+-----------+-----------+---------+------+----------+-------------------------- ---------------------------------------------------------------------------+
按照我的理解鎖應釋放第一個數據更改查詢,如更新,刪除等。
但是save()
st困境越來越嚴重,並且一直在等待。任何想法爲什麼發生這種情況?當我打電話給account.save()
時,我認爲它沒有選擇前一個事務,而是選擇更新查詢。
我錯過了一些明顯的東西嗎?請幫助。
是否使用TransactionMiddleware?這個問題是否發生在HTTP請求的上下文中? –
@AntonisChristofides否我沒有使用TransactionMiddleware。是的,它發生在HTTP請求的上下文中,但不僅僅發生在HTTP請求的上下文中。當我從django shell運行代碼時出現同樣的錯誤。 – Sudipta