PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Les curseurs dans Django s'exécutent-ils à l'intérieur de la transaction ouverte ?

Je pense que vous auriez besoin d'une connexion db distincte pour obtenir une transaction distincte et simultanée. Je suis également à peu près sûr que Django ne gère qu'une seule connexion par base de données. Mais vous pourriez en créer un autre. Il pourrait y avoir une bonne raison de ne pas le faire. La complexité vient à l'esprit.

Je pense que quelque chose comme ça fonctionnerait :

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

Notez que vous ne pouvez pas utiliser django.db.transaction car il opère sur les instances de connexion globales dans django.db.connections , mais dans tous les cas, il ne s'agit que d'une mince enveloppe autour des méthodes de gestion des transactions sur l'objet de connexion.

Je suppose que la vraie question est pourquoi voulez-vous faire cela ? ! Et qu'est-ce qui ne va pas avec la réponse de Lakshman Prasad ? Vous pouvez valider/annuler quand vous le souhaitez, donc rien ne vous empêche d'effectuer différentes tâches dans des transactions distinctes au sein d'une même vue. Le fait que les transactions doivent être parallèles et non successives suggère une connexion logique entre elles, ce qui, à mon avis, indiquerait qu'elles devraient vraiment être dans la même transaction.

Si, d'autre part, vous essayez simplement d'émuler une sorte de traitement hors ligne, dont le succès ou l'échec n'est pas du tout pertinent pour la vue, envisagez de configurer une file d'attente de messages et d'effectuer ces insertions dans un fichier séparé. traiter. Céleri est un package populaire pour faire exactement cela. Si le temps de réponse n'est pas une préoccupation majeure, cependant, je pense toujours que des transactions successives devraient suffire.

Mise à jour :

Si vous souhaitez que votre cache basé sur la base de données fonctionne en mode de validation automatique tout en exécutant votre logique métier dans une seule transaction (séparée), il existe un moyen Django. Tout ce que vous avez à faire est de vous assurer que la mise en cache se produit à l'extérieur le commit_on_success :

  • Si vous utilisez uniquement le middleware de mise en cache, assurez-vous qu'il se trouve en dehors du TransactionMiddleware .

  • Si vous utilisez des décorateurs de vue de mise en cache, je suppose que vous pouvez désactiver TransactionMiddleware (ou placez la vue du problème dans un autocommit décorateur) et utilisez le commit_on_success décorateur d'intérieur le décorateur de mise en cache. Ça a l'air drôle, mais je ne sais pas pourquoi ça ne marcherait pas :

    @transaction.autocommit
    @cache_page(500)
    @transaction.commit_on_success
    def my_view(request):
        "..."
    
  • Si vous utilisez la mise en cache de modèles ou effectuez une mise en cache manuelle plus complexe, vous pouvez également désactiver TransactionMiddleware (ou placez la vue du problème dans un autocommit décorateur) et utilisez commit_on_success en tant que gestionnaire de contexte pour ne mettre que le code dont vous avez besoin dans une transaction gérée, laissant le reste de la vue en 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)