Nachdem ich dieses Problem hatte und zwei endgültige Lösungen dafür gefunden hatte, hielt ich es für sinnvoll, eine weitere Antwort zu veröffentlichen.
Dies ist ein Problem mit dem Standardtransaktionsmodus von MySQL. Django öffnet zu Beginn eine Transaktion, was bedeutet, dass standardmäßig keine Änderungen in der Datenbank angezeigt werden.
Demonstrieren Sie so
Führen Sie eine Django-Shell in Terminal 1 aus
>>> MyModel.objects.get(id=1).my_field
u'old'
Und noch eine in Terminal 2
>>> MyModel.objects.get(id=1).my_field
u'old'
>>> a = MyModel.objects.get(id=1)
>>> a.my_field = "NEW"
>>> a.save()
>>> MyModel.objects.get(id=1).my_field
u'NEW'
>>>
Zurück zu Terminal 1, um das Problem zu demonstrieren - wir lesen immer noch den alten Wert aus der Datenbank.
>>> MyModel.objects.get(id=1).my_field
u'old'
Zeigen Sie nun in Terminal 1 die Lösung
>>> from django.db import transaction
>>>
>>> @transaction.commit_manually
... def flush_transaction():
... transaction.commit()
...
>>> MyModel.objects.get(id=1).my_field
u'old'
>>> flush_transaction()
>>> MyModel.objects.get(id=1).my_field
u'NEW'
>>>
Die neuen Daten werden jetzt gelesen
Hier ist dieser Code in einem einfach einzufügenden Block mit docstring
from django.db import transaction
@transaction.commit_manually
def flush_transaction():
"""
Flush the current transaction so we don't read stale data
Use in long running processes to make sure fresh data is read from
the database. This is a problem with MySQL and the default
transaction mode. You can fix it by setting
"transaction-isolation = READ-COMMITTED" in my.cnf or by calling
this function at the appropriate moment
"""
transaction.commit()
Die alternative Lösung besteht darin, my.cnf für MySQL zu ändern, um den Standardtransaktionsmodus zu ändern
transaction-isolation = READ-COMMITTED
Beachten Sie, dass dies eine relativ neue Funktion für MySQL ist und einige Konsequenzen für die binäre Protokollierung / Slave hat . Sie können dies auch in die Präambel der Django-Verbindung einfügen, wenn Sie möchten.
Update 3 Jahre später
Nachdem Django 1.6 Autocommit in MySQL aktiviert hat, ist dies kein Problem mehr. Das obige Beispiel funktioniert jetzt ohne den flush_transaction()
Code, unabhängig davon, ob sich MySQL in REPEATABLE-READ
(Standard) oder befindetREAD-COMMITTED
Transaktionsisolationsmodus befindet.
In früheren Versionen von Django, die im Nicht-Autocommit-Modus ausgeführt wurden, wurde in der ersten select
Anweisung eine Transaktion geöffnet. Da der Standardmodus von MySQL REPEATABLE-READ
dies ist, bedeutet dies, dass keine Aktualisierungen der Datenbank von nachfolgenden select
Anweisungen gelesen werden - daher ist dieflush_transaction()
Code , über dem die Transaktion gestoppt und eine neue gestartet wird.
Es gibt immer noch Gründe, warum Sie die READ-COMMITTED
Transaktionsisolation verwenden möchten . Wenn Sie Terminal 1 in eine Transaktion einfügen und die Schreibvorgänge von Terminal 2 anzeigen möchten, die Sie benötigen würdenREAD-COMMITTED
.
Der flush_transaction()
Code erzeugt jetzt in Django 1.6 eine Warnung vor Verfall. Ich empfehle daher, diese zu entfernen.