7

Usiamo la base dichiarativa SQLAlchemy e ho un metodo per il quale voglio isolare il livello di transazione. Per spiegare, ci sono due processi che scrivono contemporaneamente nel database e devo farli eseguire la loro logica in una transazione. Il livello di isolamento della transazione predefinito è READ COMMITTED, ma devo essere in grado di eseguire una parte di codice utilizzando i livelli di isolamento SERIALIZABLE.Come si imposta il livello di isolamento della transazione in SQLAlchemy per PostgreSQL?

Come viene fatto utilizzando SQLAlchemy? In questo momento, ho fondamentalmente un metodo nel nostro modello, che eredita dalla base dichiarativa di SQLAlchemy, che deve essenzialmente essere invocato su base transazionale.

from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT 
from psycopg2.extensions import ISOLATION_LEVEL_READ_COMMITTED 
from psycopg2.extensions import ISOLATION_LEVEL_SERIALIZABLE 

class OurClass(SQLAlchemyBaseModel): 

    @classmethod 
    def set_isolation_level(cls, level=ISOLATION_LEVEL_SERIALIZABLE): 
     cls.get_engine().connect().connection.set_isolation_level(level) 

    @classmethod 
    def find_or_create(cls, **kwargs): 
     try: 
      return cls.query().filter_by(**kwargs).one() 
     except NoResultFound: 
      x = cls(**kwargs) 
      x.save() 
      return x 

Sto facendo questo per invocare questo utilizzando un livello di isolamento della transazione, ma non sta facendo quello che mi aspetto. Il livello di isolamento è ancora READ COMMITTED da ciò che vedo nei log di Postgres. Qualcuno può aiutare a identificare ciò che sto facendo in modo sbagliato?

sto usando SQLAlchemy 0.5.5

class Foo(OurClass): 

    def insert_this(self, kwarg1=value1): 
     # I am trying to set the isolation level to SERIALIZABLE 
     try: 
      self.set_isolation_level() 
      with Session.begin(): 
       self.find_or_create(kwarg1=value1) 
     except Exception: # if any exception is thrown... 
      print "I caught an expection." 
      print sys.exc_info() 
     finally: 
      # Make the isolation level back to READ COMMITTED 
      self.set_isolation_level(ISOLATION_LEVEL_READ_COMMITTED) 

risposta

7

Da Michael Bayer, il manutentore di SQLAlchemy:

Si prega di utilizzare il "ISOLATION_LEVEL" argomento per create_engine() e utilizzare il latest tip of SQLAlchemy fino 0.6.4 viene rilasciato, in quanto vi era un psycopg2 -specifico bug corretto di recente relativo al livello di isolamento.

L'approccio avete seguito non significa influisce sulla stessa connessione, che è poi utilizzato per l'interrogazione - faresti invece utilizzare un PoolListener che imposta fino set_isolation_level su tutti collegamenti come vengono creati.

+3

Sembra che l'argomento 'isolation_level' di' create_engine() 'abbia effetto solo sul gestore delle connessioni principale in modo da ottenere quel livello di isolamento su ogni singola connessione. Hai trovato un modo compatibile con il pool di connessioni per raggiungere questo risultato per sessione/connessione? La tua domanda originale sembrava che tu lo volessi solo con un certo metodo. – Russ

-3

Il livello di isolamento si trova all'interno di una transazione, ad esempio,

try: 
    Session.begin() 
    Session.execute('set transaction isolation level serializable') 
    self.find_or_create(kwarg1=value1) 
except: 
    ... 

Da PostgreSQL doc:

Se SET operazione è eseguita senza una preventiva START TRANSACTION o BEGIN, sarà sembrano avere alcun effetto, in quanto l'operazione terminerà immediatamente.

+0

Testerò la tua risposta domani e accetto questo se funziona :) Ho la sensazione che lo farà. –

+0

La tua risposta non funziona. Secondo Michael Bayer, sembra che il livello di isolamento della transazione non stia influenzando la stessa connessione utilizzata in seguito per l'interrogazione. –

+0

Credo che il commento di Michael Bayer riguardi il tuo codice, non il mio. La differenza è che il tuo imposta il livello di isolamento prima di iniziare la transazione. Hai davvero provato il codice prima di affermare che non funziona? – sayap