Python 使用SQLAlchemy的事务和方法

Python 使用SQLAlchemy的事务和方法,python,transactions,sqlalchemy,Python,Transactions,Sqlalchemy,我有一个collection类,用于使用SQLAlchemy修改数据库中的一些数据: import sqlalchemy as sa class Collection: def __init__(self, ...): self.engine = sa.create_engine(...) def get_some_name_by_id(self, name): return self.engine.execute(select(), ...)

我有一个collection类,用于使用SQLAlchemy修改数据库中的一些数据:

import sqlalchemy as sa

class Collection:
    def __init__(self, ...):
        self.engine = sa.create_engine(...)

    def get_some_name_by_id(self, name):
        return self.engine.execute(select(), ...).fetchone().id

    def add(self, name):
        some_id = self.get_some_name_by_id(name)
        with self.engine.begin() as conn:
            conn.execute(...)
            conn.execute(...)
            conn.execute(...)
            ...
所以它有两种方法:

通过\u id获取\u some\u name \u-给定名称将返回一些id add方法使用get_some_name_by_id中的id来执行一系列SQL请求。 问题是我想在事务中包含get_some_name_by_id。起初,我有一个巨大的add方法,其中所有的执行语句都在with语句下。现在我正在重构代码,将一些块提取到方法中,我不知道如何将它们添加到事务中。如果可能的话,方法应该在事务中运行,如果它是在事务中调用的

当然,我可以这样做:

def get_some_name_by_id(self, name, conn=None):
    if conn is None:
        conn = self.engine
    return conn.execute(select(), ...).fetchone().id

def add(self, name):
    with self.engine.begin() as conn:
        some_id = self.get_some_name_by_id(name, conn)
        conn.execute(...)

但我觉得这有点笨拙。我将得到很多函数,它们都有相同的if子句。有更好的办法吗

我认为你建议的方法还可以。您可以使用@property decorator为conn实现自定义检索: 例如:

import sqlalchemy as sa

class Collection(object):
    def __init__(self, ...):
        self.engine = sa.create_engine(...)
        self._conn = None

    @property
    def conn(self):
        if self._conn is None:
            self._conn = self.engine
        return self._conn

    @conn.setter
    def conn(self, value):
        self._conn = value

    def get_some_name_by_id(self, name):
        return self.conn.execute(select(), ...).fetchone().id

    def add(self, name):
        with self.engine.begin() as self.conn:
            some_id = self.get_some_name_by_id(name)
            self.conn.execute(...)

这样你就不必绕过康恩了。您可以初始化self.conn一次并使用它,因为每个集合对象只能有一个连接。如果需要,您可以修改它以支持多个连接。

Hm,有趣的解决方案。使用块后,self.conn将变为“无”或“无”?self.conn仍将是连接对象,但如果不调用self.conn.begin,您将无法将其用于任何其他查询。查看调用begin时发生的情况这很糟糕。因为这意味着我不能在没有事务的情况下使用get\u some\u name\u by\u id。您仍然可以在事务之外使用get\u some\u name\u by\u id作为独立的。在“添加”结束时,必须将self.conn设置为“无”。因此,下次访问self.conn时,它将返回self.engine和.execute…fetchone。。。仍然有效。