Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python SQLAlchemy连接错误_Python_Multithreading_Sqlalchemy - Fatal编程技术网

Python SQLAlchemy连接错误

Python SQLAlchemy连接错误,python,multithreading,sqlalchemy,Python,Multithreading,Sqlalchemy,我遇到了一些奇怪的bug,这些bug似乎是由Sqlalchemy使用的连接引起的,我无法准确地确定。。我希望有人知道这里发生了什么 我们正在开发一个金字塔(版本1.5b1),并将Sqlalchemy(版本0.9.6)用于所有数据库连接。有时我们会收到与db连接或会话相关的错误,大多数情况下这可能是光标已关闭或此连接已关闭错误,但我们也会收到其他相关异常: (OperationalError) connection pointer is NULL (InterfaceError) cursor a

我遇到了一些奇怪的bug,这些bug似乎是由Sqlalchemy使用的连接引起的,我无法准确地确定。。我希望有人知道这里发生了什么

我们正在开发一个金字塔(版本1.5b1),并将Sqlalchemy(版本0.9.6)用于所有数据库连接。有时我们会收到与db连接或会话相关的错误,大多数情况下这可能是
光标已关闭
此连接已关闭
错误,但我们也会收到其他相关异常:

(OperationalError) connection pointer is NULL
(InterfaceError) cursor already closed
Parent instance <...> is not bound to a Session, and no contextual session is established; lazy load operation of attribute '...' cannot proceed

A conflicting state is already present in the identity map for key (<class '...'>, (1001L,))
This Connection is closed (original cause: ResourceClosedError: This Connection is closed)
(InterfaceError) cursor already closed
Parent instance <...> is not bound to a Session; lazy load operation of attribute '...' cannot proceed
Parent instance <...> is not bound to a Session, and no contextual session is established; lazy load operation of attribute '...' cannot proceed
'NoneType' object has no attribute 'twophase'
(OperationalError) connection pointer is NULL
This session is in 'prepared' state; no further
  • 我们的所有orm对象都有一个基本模型:

    BaseModel=declarative_base(cls=BaseModelObj,metaclass=BaseMeta,metadata=db_meta)

  • 我们使用pyramid_tm tween来处理请求期间的事务

  • 我们将db_session.remove()挂接到pyramid NewResponse事件(在一切运行之后触发)。我还试着把它放在一个单独的二人组中,在pyramid_tm之后运行,甚至根本不做,这些似乎都没有效果,所以响应事件似乎是放置它的最干净的地方

  • 我们在金字塔项目的主入口点创建引擎,并使用空池,将连接池留给pgbouncer。我们还在此处为BaseModel配置会话和绑定:

    engine=engine\u from_config(config.registry.settings,'sqlalchemy',poolclass=NullPool) db\u session.configure(bind=engine,query\u cls=FilterQuery) BaseModel.metadata.bind=引擎 config.add_订阅服务器(清理\u db_会话,NewResponse) return config.make_wsgi_app()

  • 在我们的应用程序中,我们使用以下方式访问所有数据库操作:

    从project.db导入db_会话 ... db_session.query(MyModel).filter(…) db_session.execute(…)

  • 我们使用psycopg2==2.5.2来处理到postgres的连接,pgbouncer介于两者之间

  • 我确保对db_会话或连接的引用不会保存在任何地方(这可能会导致其他线程重用它们)

我还使用不同的Web服务器尝试了垃圾邮件测试,使用Waiteress和cogen,我很容易得到错误,使用wsgiref,我们毫不奇怪没有错误(这是单线程的)。使用uwsgi和gunicorn(4名工人,gevent),我没有得到任何错误

考虑到所使用的Web服务器的差异,我认为这要么与一些Web服务器在线程中处理请求有关,要么与一些使用新进程有关(可能是分叉问题)?更复杂的是,随着时间的推移,我做了一些新的测试,问题在女服务员身上消失了,但现在发生在gunicorn身上(使用gevent时)!我不知道如何调试这个

最后,为了测试连接发生了什么,我在游标execute开始时为连接附加了一个属性,并尝试在execute结束时读取该属性:

@event.listens_for(Engine, "before_cursor_execute")
def _before_cursor_execute(conn, cursor, stmt, params, context, execmany):
  conn.pdtb_start_timer = time.time()

@event.listens_for(Engine, "after_cursor_execute")
def _after_cursor_execute(conn, cursor, stmt, params, context, execmany):
  print conn.pdtb_start_timer
令人惊讶的是,这有时会引发异常:“Connection”对象没有属性“pdtb\u start\u timer”

这让我觉得很奇怪。。我发现了一个类似的讨论: 并尝试将strategy='threadlocal'添加到引擎中,据我所知,这将强制踏板连接1。但是这对我看到的错误没有任何影响。。(除了一些单元测试失败之外,因为我需要两个不同的会话/连接来进行一些测试,这将强制关联1个连接)

有没有人知道这里会发生什么,或者对如何解决这个问题有更多的建议

提前谢谢


Matthijs Blaas

更新:多个命令在一条准备好的sql语句中发送所导致的错误。Psycopg2似乎允许这样做,但显然它会导致奇怪的问题。PG8000连接器对多个命令要求更严格,发送一个命令解决了问题

我有一个关于这个问题的更新,现在我只在gevent模式下使用gunicorn,一致地得到“(InterfaceError)游标已关闭”异常:
@event.listens_for(Engine, "before_cursor_execute")
def _before_cursor_execute(conn, cursor, stmt, params, context, execmany):
  conn.pdtb_start_timer = time.time()

@event.listens_for(Engine, "after_cursor_execute")
def _after_cursor_execute(conn, cursor, stmt, params, context, execmany):
  print conn.pdtb_start_timer