为什么在SQLAlchemy中不鼓励这种模式?

时间:2017-08-07 00:10:09

标签: multithreading sqlalchemy

在阅读官方SQLAlchemy文档时,我找到了以下示例:

### this is the **wrong way to do it** ###

class ThingOne(object):
    def go(self):
        session = Session()
        try:
            session.query(FooBar).update({"x": 5})
            session.commit()
        except:
            session.rollback()
            raise

class ThingTwo(object):
    def go(self):
        session = Session()
        try:
            session.query(Widget).update({"q": 18})
            session.commit()
        except:
            session.rollback()
            raise

def run_my_program():
    ThingOne().go()
    ThingTwo().go()

我真的不明白这种模式的缺点。实际上我可以想到一个主要的优点:在多线程上下文中,这种模式可以确保每个会话实例都是实际使用它的函数的局部变量。

有人可以通过给出上面例子的一些潜在缺点来启发我吗?感谢。

编辑:作为多线程上下文优势的示例。如果我们在这里有一个Web应用程序服务器类:

class WebApp:
  def update(self, **kwargs):
    session = Session()
    try:...

这里,页面处理程序update有自己的局部变量session,因此无论它运行多少线程,它总是安全的。相反,使用另一个函数层来包含session会在这种情况下引入更复杂的方法

1 个答案:

答案 0 :(得分:-1)

简单来说,sqlalchemy建议会话的处理不要与数据的操作混合在一起。正如您在下一个示例中所看到的那样。

### this is a **better** (but not the only) way to do it ###

class ThingOne(object):
    def go(self, session):
        session.query(FooBar).update({"x": 5})

class ThingTwo(object):
    def go(self, session):
        session.query(Widget).update({"q": 18})

def run_my_program():
    session = Session()
    try:
        ThingOne().go(session)
        ThingTwo().go(session)

        session.commit()
    except:
        session.rollback()
        raise
    finally:
        session.close()

ThingOne和ThingTwo正在做CRUD,但会话的处理是在这些对象之外完成的。

对于多线程,会话范围是线程本地对象。意思是,它们不能被不同的线程共享。您可以将它们声明为您指定的内容,但这并不意味着从外部实体处理会话也是不好的选择。