Auswählen für Update-Abfrage: Lock wait timeout überschritten Fehler

Um Race-Bedingungen zu vermeiden, muss ich select for update Funktionalität verwenden, während die Datenbank abgefragt, so dass es die Zeile bis zum Ende der Transaktion sperrt. Da select_for_update Abfrage nicht in Django 1.3 vorhanden ist, habe ich eine Problemumgehung durchgeführt, indem ich eine Klassenmethode verwende, die Abfragesätze zurückgibt, indem sie eine rohe SQL-Abfrage ausführt.

 #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] 

Dies ist, wie es in Ansichten verwendet wird.

 account = AccountDetails.get_locked_for_update(userid) account.amount = account.amount - fare account.save() 

Auf der letzten Zeile bekomme ich diesen Fehler: OperationalError: (1205, 'Lock wait timeout exceeded; try restarting transaction')

In dbshell, nach dem Ausführen der save() Zeile:

 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 | +-----+------+-----------+-----------+---------+------+----------+-------------------------- ---------------------------------------------------------------------------+ 

Nach meinem Verständnis sollte die Sperre auf der ersten Datenänderung abgefragt werden, wie zB Update, Löschen usw.

Aber die save() Anweisung wird blockiert und wird immer warten. Irgendeine Idee, warum dies geschieht? Was ich denke, ist, wenn ich account.save() es ist nicht abholen die vorherige Transaktion gestartet von select für Update-Abfrage.

Bin ich etwas offensichtlich fehlt? Freundlich helfen.

2 Solutions collect form web for “Auswählen für Update-Abfrage: Lock wait timeout überschritten Fehler”

Das Verlassen von Django zu seinem Standard-Autocommit-ähnlichen Verhalten für eine solche Operation kann leicht zu mehreren Arten von Fehlern führen (nicht die Sperrung der Datenbank überhaupt könnte leicht ein anderes Ergebnis sein); Die Details hängen wahrscheinlich vom RDBMS- und / oder Django-Datenbanktreiber für das jeweilige RDBMS ab. Es wäre besser, @commit_on_success oder @commit_manually oder TransactionMiddleware .

Ich denke, ein anderer Thread hält eine Rekord-Sperre auf einige Rekord zu lange, und Ihr Thread wird aus diesem Problem ein Problem spezifisch für MYSQL, die nicht unterstützt nowait.

Sie können einen höheren Wert für innodb_lock_wait_timeout und innodb_lock_wait_timeout neu starten

  • Asynchrone Steckdosen mit Auswahl - Python
  • Können pygame-Events in select.select-Eingabeliste behandelt werden?
  • Pyodbc - Wie man eine select-Anweisung mit einer Variablen für einen Parameter ausführt
  • Python ist die beste Programmiersprache der Welt.