0

在我的应用程序中,我使用 SQLAlchemy 在应用程序重新启动时存储大多数持久数据。为此,我有一个db包,其中包含我的映射器类(如TagGroup)和一个支持类create_engineSession使用sessionmaker.

现在我对如何使用 SQLAlchemys 会话的理解是,我不会在我的应用程序中传递它们,而是在需要访问数据库时使用全局工厂创建实例。

这会导致在一个会话中查询记录,然后将其传递到应用程序的另一部分,该部分使用不同的会话实例。这给了我这样的例外:

Traceback (most recent call last):
  File "…", line 29, in delete
    session.delete(self.record)
  File "/usr/lib/python3.3/site-packages/sqlalchemy/orm/session.py", line 1444, in delete
    self._attach(state, include_before=True)
  File "/usr/lib/python3.3/site-packages/sqlalchemy/orm/session.py", line 1748, in _attach
    state.session_id, self.hash_key))
sqlalchemy.exc.InvalidRequestError: Object '<Group at 0x7fb64c7b3f90>' is already attached to session '1' (this is '3')

现在我的问题是:我是否Session完全错误地使用了(所以我应该一次只使用一个会话并将该会话与数据库中的记录一起传递给其他组件)或者这可能是实际代码问题的结果吗?

一些示例代码演示了我的确切问题:

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base, declared_attr

Base = declarative_base()

class Record(Base):
    __tablename__ = "record"

    id = Column(Integer, primary_key=True)
    name = Column(String)

    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return "<%s('%s')>" % (type(self).__name__, self.name)

engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)

Session = sessionmaker(bind=engine)

s1 = Session()

record = Record("foobar")
s1.add(record)
s1.commit()

# This would be a completly different part of app

s2 = Session()

record = s2.query(Record).filter(Record.name == "foobar").first()

def delete_record(record):
    session = Session()
    session.delete(record)
    session.commit()

delete_record(record)
4

1 回答 1

0

现在我切换到使用单个全局会话实例。在我看来,这既不好也不干净,但是包括大量的样板代码来从一个会话中删除对象只是为了在将其移交给其他应用程序部分之后将它们添加回原来的会话也不是现实的选择。

我想如果我开始使用多个线程通过同一个会话访问数据库,这将彻底崩溃……</p>

于 2013-06-01T17:55:48.070 回答