【问题标题】:How do I set the transaction isolation level in SQLAlchemy for PostgreSQL?如何在 SQLAlchemy for PostgreSQL 中设置事务隔离级别?
【发布时间】:2011-03-31 22:30:09
【问题描述】:

我们正在使用 SQLAlchemy 声明式基础,并且我有一个方法要隔离事务级别。解释一下,有两个进程同时写入数据库,我必须让它们在事务中执行它们的逻辑。默认事务隔离级别是 READ COMMITTED,但我需要能够使用 SERIALIZABLE 隔离级别执行一段代码。

这是如何使用 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

我这样做是为了使用事务隔离级别来调用它,但它并没有达到我的预期。从我在 postgres 日志中看到的内容来看,隔离级别仍然是 READ COMMITTED。有人可以帮助确定我做错了什么吗?

我正在使用 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)

【问题讨论】:

    标签: python postgresql transactions sqlalchemy isolation-level


    【解决方案1】:

    来自 SQLAlchemy 的维护者 Michael Bayer:

    请使用“isolation_level” 参数create_engine() 并使用latest tip of SQLAlchemy 直到 0.6.4 发布,因为有 最近修复了一个特定于 psycopg2 的错误 关于隔离级别。

    你下面的方法没有 影响相同的连接 后来用于查询 - 你会 而是使用设置的 PoolListener 全部设置 set_isolation_level 创建时的连接。

    【讨论】:

    • 似乎isolation_levelcreate_engine() 参数只影响主连接管理器,因此您可以在每个连接上获得该隔离级别。您是否找到了一种与连接池兼容的方法来在每个会话/连接的基础上实现这一目标?您最初的问题似乎只是在某种方法上想要它。
    【解决方案2】:

    隔离级别在事务中设置,例如

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

    来自PostgreSQL doc

    如果 SET TRANSACTION 在没有事先 START TRANSACTION 或 BEGIN 的情况下执行,它似乎没有任何效果,因为事务将立即结束。

    【讨论】:

    • 明天我会测试你的答案,如果可行,我会接受它:) 我觉得它会的。
    • 您的回答无效。根据 Michael Bayer 的说法,事务隔离级别似乎不会影响稍后用于查询的同一连接。
    • 我相信 Michael Bayer 的评论是关于你的代码,而不是我的。不同之处在于您在开始事务之前设置了隔离级别。在声称它不起作用之前,您真的尝试过代码吗?
    • 是的,它没有用。问题是,当我在 Session 中执行它时,查询不会在同一个事务中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-20
    • 1970-01-01
    • 2015-09-25
    • 2012-04-22
    • 2015-03-26
    • 2011-12-17
    • 1970-01-01
    相关资源
    最近更新 更多