7

Мы используем декларативную базу SQLAlchemy, и у меня есть метод, для которого я хочу изолировать уровень транзакции. Чтобы объяснить, есть два процесса, которые одновременно записываются в базу данных, и я должен заставить их выполнить свою логику в транзакции. Уровень изоляции транзакции по умолчанию - READ COMMITTED, но мне нужно выполнить кусок кода, используя уровни изоляции SERIALIZABLE.Как установить уровень изоляции транзакций в SQLAlchemy для PostgreSQL?

Как это делается с помощью SQLAlchemy? Прямо сейчас у меня в основном есть метод в нашей модели, который наследуется от декларативной базы SQLAlchemy, которая по существу нуждается в транзакционном вызове.

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 

Я делаю это, чтобы использовать это, используя уровень изоляции транзакции, но это не делает то, что я ожидаю. Уровень изоляции по-прежнему READ COMMITTED из того, что я вижу в журналах postgres. Может ли кто-нибудь помочь определить, что я делаю?

Я использую 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) 

ответ

7

От Майкла Байера, сопровождающему SQLAlchemy:

Пожалуйста, используйте "isolation_level" аргумент create_engine() и использовать latest tip of SQLAlchemy до 0.6.4 будет выпущен, как было psycopg2 -специфическая ошибка, исправленная недавно относительно уровня изоляции.

Подход у вас есть ниже, не влияет на то же самое соединение, которое позже используется для запроса - вы бы вместо этого использовать PoolListener, который устанавливает до set_isolation_level на всех соединений, как они созданы.

+3

Кажется, что аргумент 'isol_level'' create_engine() 'влияет только на главный диспетчер соединений, поэтому вы получаете этот уровень изоляции для каждого соединения. Вы определили способ объединения соединений с пулом для достижения этого на основе сеанса/соединения? Ваш оригинальный вопрос казался вам, что вы только хотели его по определенному методу. – Russ

-3

Уровень изоляции устанавливается в рамках транзакции, например,

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

От PostgreSQL doc:

Если SET TRANSACTION выполняется без предварительного START TRANSACTION или BEGIN, которая будет отображаться не иметь никакого эффекта, так как сделка будет немедленно прекратить.

+0

Я буду проверять ваш ответ завтра и принять это, если он работает :) У меня такое чувство. –

+0

Ваш ответ не работает. По словам Майкла Байера, похоже, что уровень изоляции транзакций не влияет на то же соединение, которое позже используется для запросов. –

+0

Я считаю, что комментарий Майкла Байера касается вашего кода, а не моего. Разница заключается в том, что вы установили уровень изоляции перед началом транзакции. Вы действительно пробовали код, прежде чем заявить, что он не работает? – sayap

Смежные вопросы