PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Laufen Cursor in Django innerhalb der offenen Transaktion?

Ich glaube, Sie benötigen eine separate DB-Verbindung, um eine separate, gleichzeitige Transaktion zu erhalten. Ich bin mir auch ziemlich sicher, dass Django nur eine Verbindung pro Datenbank verwaltet. Aber du könntest einen anderen erstellen. Es könnte einen guten Grund geben, dies nicht zu tun. Komplexität kommt mir in den Sinn.

Ich denke, so etwas würde funktionieren:

from django.conf import settings
from django.db.utils import ConnectionHandler

def my_view(request):
    """Flirt with complexity by using two connections to db"""
    private_connections = ConnectionHandler(settings.DATABASES)
    db = router.db_for_write(model)
    new_conn = private_connections[db]
    new_conn.enter_transaction_management()
    new_conn.managed(True)
    new_cur = new_conn.cursor()
    new_cur.execute("INSERT INTO ...")
    new_conn.commit()
    new_conn.close()

Beachten Sie, dass Sie django.db.transaction nicht verwenden können weil es auf den globalen Verbindungsinstanzen in django.db.connections arbeitet , aber auf jeden Fall ist das nur ein dünner Wrapper um die Transaktionsverwaltungsmethoden auf dem Verbindungsobjekt.

Ich denke, die eigentliche Frage ist warum willst du das tun?! Und was ist falsch an Lakshman Prasads Antwort? Sie können Commit/Rollback ausführen, wann immer Sie möchten, sodass Sie nichts daran hindert, verschiedene Aufgaben in unterschiedlichen Transaktionen innerhalb einer einzigen Ansicht auszuführen. Die Tatsache, dass die Transaktionen parallel und nicht aufeinanderfolgend sein müssen, deutet auf eine logische Verbindung zwischen ihnen hin, die meiner Meinung nach darauf hindeuten würde, dass sie sich wirklich in derselben Transaktion befinden sollten.

Wenn Sie andererseits nur versuchen, eine Art Offline-Verarbeitung zu emulieren, deren Erfolg oder Misserfolg für die Ansicht überhaupt nicht relevant ist, sollten Sie erwägen, eine Nachrichtenwarteschlange einzurichten und diese Einfügungen in einer separaten auszuführen Prozess. Sellerie ist ein beliebtes Paket, um genau das zu tun. Wenn die Antwortzeit kein großes Problem darstellt, denke ich jedoch, dass aufeinanderfolgende Transaktionen ausreichen sollten.

Aktualisierung:

Wenn Sie möchten, dass Ihr datenbankgestützter Cache im Autocommit-Modus arbeitet, während Ihre Geschäftslogik weiterhin in einer einzigen (separaten) Transaktion ausgeführt wird, gibt es einen Django-Weg. Sie müssen lediglich sicherstellen, dass das Caching außerhalb erfolgt der commit_on_success :

  • Wenn Sie nur die Caching-Middleware verwenden, stellen Sie sicher, dass sie sich außerhalb der TransactionMiddleware befindet .

  • Wenn Sie Caching-View-Decorators verwenden, wage ich zu vermuten, dass Sie TransactionMiddleware deaktivieren könnten (oder fügen Sie die Problemansicht in ein autocommit ein decorator) und verwenden Sie den commit_on_success Dekorateur innen der Cache-Dekorateur. Es sieht komisch aus, aber ich weiß nicht, warum es nicht funktionieren sollte:

    @transaction.autocommit
    @cache_page(500)
    @transaction.commit_on_success
    def my_view(request):
        "..."
    
  • Wenn Sie Vorlagen-Caching verwenden oder aufwendigeres manuelles Caching durchführen, können Sie TransactionMiddleware auch deaktivieren (oder fügen Sie die Problemansicht in ein autocommit ein decorator) und verwenden Sie commit_on_success als Kontextmanager, um nur den benötigten Code in eine verwaltete Transaktion einzufügen und den Rest der Ansicht in Autocommit zu belassen.

    @transaction.autocommit
    def my_view(request):
        data = cache.get(some_key)
        with transaction.commit_on_success():
            context = do_some_processing(data)
        cache.set(some_key, context['data'])
        return render('template/with/cache/blocks.html', context=context)