7

Wir verwenden die deklarative SQLAlchemy-Basis und ich habe eine Methode, für die ich die Transaktionsebene isolieren möchte. Um dies zu erklären, schreiben zwei Prozesse gleichzeitig in die Datenbank und ich muss sie ihre Logik in einer Transaktion ausführen lassen. Die Standardtransaktionsisolationsstufe ist READ COMMITTED, aber ich muss in der Lage sein, einen Codeabschnitt mit SERIALIZABLE-Isolationsstufen auszuführen.Wie lege ich die Transaktionsisolationsstufe in SQLAlchemy für PostgreSQL fest?

Wie erfolgt dies mit SQLAlchemy? Im Moment habe ich im Grunde eine Methode in unserem Modell, die von der deklarativen Basis von SQLAlchemy erbt, die im Wesentlichen transaktional aufgerufen werden muss.

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 

Ich mache dies, um dies mit einer Transaktionsisolationsstufe aufzurufen, aber es tut nicht, was ich erwarte. Die Isolationsstufe ist immer noch READ COMMITTED von dem, was ich in den Postgres-Logs sehe. Kann jemand helfen herauszufinden, was ich falsch mache?

Ich verwende 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) 

Antwort

7

Von Michael Bayer, den Betreuer des SQLAlchemy:

Bitte benutzen Sie den "isolation_level" Argument create_engine() und verwenden Sie die latest tip of SQLAlchemy bis 0.6.4 freigegeben wird, so war es ein psycopg2 -spezifischer Fehler behoben in Bezug auf Isolationsstufe.

Der Ansatz, den Sie unten nicht über wirken sich auf die gleiche Verbindung, die für die Abfrage verwendet später - man stattdessen eine PoolListener verwenden würde, die bis set_isolation_level auf allen Verbindungen setzt, wie sie erstellt werden.

+3

Es scheint, dass das 'isolation_level'-Argument für' create_engine() 'nur den Hauptverbindungsmanager betrifft, so dass Sie diese Isolationsstufe für jede einzelne Verbindung erhalten. Haben Sie eine Verbindungspooling-kompatible Möglichkeit gefunden, dies pro Sitzung/Verbindung zu erreichen? Deine ursprüngliche Frage schien so, als ob du sie nur auf einer bestimmten Methode haben wolltest. – Russ

-3

Die Isolationsstufe innerhalb einer Transaktion festgelegt ist, z.B.

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

Von PostgreSQL doc:

Wenn SET TRANSACTION ohne vorherigen START TRANSACTION ausgeführt wird, oder beginnt, wird es scheint keine Wirkung zu haben, da die Transaktion sofort zu beenden.

+0

Ich werde Ihre Antwort morgen testen und akzeptieren, wenn es funktioniert :) Ich habe das Gefühl, dass es wird. –

+0

Ihre Antwort funktioniert nicht. Laut Michael Bayer scheint die Transaktionsisolationsstufe nicht dieselbe Verbindung zu beeinflussen, die später für die Abfrage verwendet wird. –

+0

Ich glaube, Michael Bayers Kommentar bezieht sich auf deinen Code, nicht auf meinen. Der Unterschied besteht darin, dass Sie vor dem Starten der Transaktion die Isolationsstufe festlegen. Haben Sie den Code wirklich ausprobiert, bevor Sie behaupten, dass er nicht funktioniert? – sayap