2010-08-19 10 views
7

Estamos utilizando la base declarativa SQLAlchemy y tengo un método para el que quiero aislar el nivel de transacción. Para explicar, hay dos procesos que escriben simultáneamente en la base de datos y debo hacer que ejecuten su lógica en una transacción. El nivel de aislamiento de transacción predeterminado es LECTURA COMPROMETIDA, pero necesito poder ejecutar un fragmento de código usando niveles de aislamiento SERIALIZABLES.¿Cómo configuro el nivel de aislamiento de transacción en SQLAlchemy para PostgreSQL?

¿Cómo se hace esto con SQLAlchemy? En este momento, básicamente tengo un método en nuestro modelo, que hereda de la base declarativa de SQLAlchemy, que esencialmente necesita ser invocado transaccionalmente.

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 

Estoy haciendo esto para invocar esta usando un nivel de aislamiento de transacción, pero no está haciendo lo que espero. El nivel de aislamiento aún se LEA COMPROMETIDO por lo que veo en los registros de postgres. ¿Alguien puede ayudarme a identificar lo que estoy haciendo mal?

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

Respuesta

7

De Michael Bayer, el mantenedor de SQLAlchemy:

utilice por favor "isolation_level" argumento para create_engine() y utilizar el latest tip of SQLAlchemy hasta 0.6.4 se libera, ya que no había un psycopg2 error específico resuelto recientemente con respecto al nivel de aislamiento.

El enfoque que tiene a continuación no afectan la misma conexión que es usado más adelante para consultar - és en lugar de utilizar un PoolListener que establece hasta set_isolation_level en todos conexiones a medida que se crean.

+3

Parece que el argumento 'isolation_level' de' create_engine() 'solo afecta al administrador de conexión principal, por lo que obtiene ese nivel de aislamiento en todas y cada una de las conexiones. ¿Encontraste una forma compatible con la agrupación de conexiones para lograr esto por sesión/conexión? Tu pregunta original parecía que solo la querías en cierto método. – Russ

-3

El nivel de aislamiento se establece dentro de una transacción, por ejemplo

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

De PostgreSQL doc:

Si SET operación se ejecuta sin realizar una transacción START antes o comenzar, se parecen tener ningún efecto, ya que la transacción terminará inmediatamente.

+0

Voy a probar su respuesta mañana y aceptar esto si funciona :) Tengo la sensación de que lo hará. –

+0

Tu respuesta no funciona. Según Michael Bayer, parece que el nivel de aislamiento de transacción no está afectando a la misma conexión que luego se usa para consultar. –

+0

Creo que el comentario de Michael Bayer es sobre tu código, no el mío. La diferencia es que la suya establece el nivel de aislamiento antes de comenzar la transacción. ¿Realmente has probado el código antes de reclamar que no funciona? – sayap

Cuestiones relacionadas