2015-11-13 34 views
5

Negli ambienti di produzione in cui Django è in esecuzione su Apache o con più dipendenti di Gunicorn, si corre il rischio di problemi di concorrenza.Come eseguire blocchi di tabella/riga in Django

Come tale, sono stato piuttosto sorpreso di scoprire che l'ORM di Django non supporta esplicitamente il blocco di tabella/riga. Supporta le transazioni molto rapidamente, ma questo risolve solo la metà del problema di concorrenza.

Con un backend MySQL, qual è il modo corretto di eseguire il blocco in Django? O c'è qualcos'altro in gioco nella struttura di Django che li rende non necessari?

risposta

8

Django non fornisce esplicitamente un'API per eseguire il blocco delle tabelle. Nella mia esperienza, il codice ben progettato raramente ha bisogno di bloccare un'intera tabella e la maggior parte dei problemi di concorrenza può essere risolta con il blocco a livello di riga. È uno sforzo estremo: non risolve la concorrenza, semplicemente uccide qualsiasi tentativo di concorrenza.

Se si ha realmente bisogno di blocco a livello di tabella, è possibile utilizzare un cursore ed eseguire istruzioni SQL prime:

from django.db import connection 

with connection.cursor() as cursor: 
    cursor.execute("LOCK TABLES %s READ", [tablename]) 
    try: 
     ... 
    finally: 
     cursor.execute("UNLOCK TABLES;") 
+0

Grazie! Le mie scuse, in realtà non mi sono reso conto che continuavo a dire "serrature da tavolo", in altre parole intendevo le serrature in generale come le serrature di fila. I blocchi di riga sono in realtà ciò che sto cercando in questo caso specifico perché, come hai detto, i blocchi dei tavoli sono molto costosi. –

+0

@LukeSapan In questo caso dovresti leggere i livelli di isolamento. Nella maggior parte dei livelli di isolamento, un'istruzione di scrittura in una transazione acquisisce automaticamente un lock 'WRITE' fino alla fine della transazione. – knbk

+0

E per una situazione in cui SELEZIONA prima e poi esegui una o più scritture in base alla riga selezionata? –

0

Considerare l'impostazione del livello di isolamento transazione serializzabile, e l'utilizzo di un tipo di tabella di MySQL che supporta le transazioni (MyISAM non funziona, InnoDB.)

Dopo aver verificato che un back-end supporti le transazioni, è necessario disabilitare l'autocommit (https://docs.djangoproject.com/en/1.8/topics/db/transactions/#autocommit-details) e assicurarsi che il codice rilasci l'istruzione di commit o rollback appropriata alla fine di cosa consideri transazioni.

c'è un esempio o due nei documenti sopra citati ..

Fare questo richiede un po 'più di lavoro e la considerazione, ma si dà transazioni.