PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

I cursori in Django vengono eseguiti all'interno della transazione aperta?

Credo che avresti bisogno di una connessione db separata per ottenere una transazione separata e simultanea. Sono anche abbastanza sicuro che django gestisce solo una connessione per database. Ma potresti crearne un altro. Potrebbero esserci delle buone ragioni per non farlo. Mi viene in mente la complessità.

Penso che qualcosa del genere funzionerebbe:

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()

Nota che non puoi utilizzare django.db.transaction perché opera sulle istanze di connessione globali in django.db.connections , ma in ogni caso, questo è solo un sottile wrapper attorno ai metodi di gestione delle transazioni sull'oggetto connessione.

Immagino che la vera domanda sia perché vuoi farlo?! E cosa c'è di sbagliato nella risposta di Lakshman Prasad? Puoi eseguire il commit/rollback quando vuoi, quindi non c'è nulla che ti impedisca di eseguire attività diverse in transazioni distinte all'interno di un'unica vista. Il fatto che le transazioni debbano essere parallele e non successive suggerisce una qualche connessione logica tra di loro, che a mio avviso indicherebbe che dovrebbero davvero trovarsi nella stessa transazione.

Se, d'altra parte, stai solo cercando di emulare una sorta di elaborazione offline, il cui successo o fallimento non è particolarmente rilevante per la visualizzazione, considera l'impostazione di una coda di messaggi e l'esecuzione di questi inserimenti in un processi. Sedano è un pacchetto popolare per fare proprio questo. Se il tempo di risposta non è un problema importante, tuttavia, penso comunque che le transazioni successive dovrebbero essere sufficienti.

Aggiornamento:

Se vuoi che la tua cache supportata dal database funzioni in modalità autocommit mentre stai ancora eseguendo la tua logica aziendale in una singola transazione (separata), c'è un modo django. Tutto quello che devi fare è assicurarti che la memorizzazione nella cache avvenga all'esterno il commit_on_success :

  • Se stai solo utilizzando il middleware di memorizzazione nella cache, assicurati che sia esterno a TransactionMiddleware .

  • Se usi i decoratori di visualizzazione della cache, mi permetto di indovinare che potresti disabilitare TransactionMiddleware (o inserisci la visualizzazione del problema all'interno di un autocommit decorator) e usa il commit_on_success decoratore dentro il decoratore di cache. Sembra divertente, ma non so perché non funzionerebbe:

    @transaction.autocommit
    @cache_page(500)
    @transaction.commit_on_success
    def my_view(request):
        "..."
    
  • Se utilizzi la memorizzazione nella cache dei modelli o la memorizzazione nella cache manuale più complessa, puoi anche disabilitare TransactionMiddleware (o inserisci la visualizzazione del problema all'interno di un autocommit decorator) e usa commit_on_success come gestore del contesto per inserire solo il codice di cui hai bisogno in una transazione gestita, lasciando il resto della vista in autocommit.

    @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)