Python 为什么我的作用域会话会引发AttributeError:';会议';对象没有属性';拆下';
我试图建立一个系统,将数据库操作优雅地延迟到一个单独的线程,以避免在扭曲回调期间阻塞 到目前为止,我的方法如下:Python 为什么我的作用域会话会引发AttributeError:';会议';对象没有属性';拆下';,python,sqlalchemy,Python,Sqlalchemy,我试图建立一个系统,将数据库操作优雅地延迟到一个单独的线程,以避免在扭曲回调期间阻塞 到目前为止,我的方法如下: from contextlib import contextmanager from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session, sessionmaker from twisted.internet.threads import deferToThread _engine
from contextlib import contextmanager
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from twisted.internet.threads import deferToThread
_engine = create_engine(initialization_string)
Session = scoped_session(sessionmaker(bind=_engine))
@contextmanager
def transaction_context():
session = Session()
try:
yield session
session.commit()
except:
# No need to do session.rollback(). session.remove will do it.
raise
finally:
session.remove()
def threaded(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
return deferToThread(fn, *args, **kwargs)
return wrapper
这应该允许我使用线程化的
装饰器包装函数,然后在所述函数体中使用事务上下文
上下文管理器。以下是一个例子:
from __future__ import print_function
from my_lib.orm import User, transaction_context, threaded
from twisted.internet import reactor
@threaded
def get_n_users(n):
with transaction_context() as session:
return session.query(User).limit(n).all()
if __name__ == '__main__':
get_n_users(n).addBoth(len)
reactor.run()
但是,当我运行上述脚本时,我得到一个包含以下回溯的失败:
Unhandled error in Deferred:
Unhandled Error
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 781, in __bootstrap
self.__bootstrap_inner()
File "/usr/lib/python2.7/threading.py", line 808, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/threading.py", line 761, in run
self.__target(*self.__args, **self.__kwargs)
--- <exception caught here> ---
File "/usr/local/lib/python2.7/dist-packages/twisted/python/threadpool.py", line 191, in _worker
result = context.call(ctx, function, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/twisted/python/context.py", line 118, in callWithContext
return self.currentContext().callWithContext(ctx, func, *args, **kw)
File "/usr/local/lib/python2.7/dist-packages/twisted/python/context.py", line 81, in callWithContext
return func(*args,**kw)
File "testaccess.py", line 9, in get_n_users
return session.query(User).limit(n).all()
File "/usr/lib/python2.7/contextlib.py", line 24, in __exit__
self.gen.next()
File "/home/louis/Documents/Python/knacki/knacki/db.py", line 36, in transaction_context
session.remove()
exceptions.AttributeError: 'Session' object has no attribute 'remove'
延迟中未处理的错误:
未处理错误
回溯(最近一次呼叫最后一次):
文件“/usr/lib/python2.7/threading.py”,第781行,在引导程序中
self.\uuu引导\u内部()
文件“/usr/lib/python2.7/threading.py”,第808行,在引导程序内部
self.run()
文件“/usr/lib/python2.7/threading.py”,第761行,正在运行
自我目标(*自我参数,**自我参数)
--- ---
文件“/usr/local/lib/python2.7/dist-packages/twisted/python/threadpool.py”,第191行,in\u-worker
结果=context.call(ctx、函数、*args、**kwargs)
callWithContext中的文件“/usr/local/lib/python2.7/dist-packages/twisted/python/context.py”,第118行
返回self.currentContext().callWithContext(ctx,func,*args,**kw)
callWithContext中的文件“/usr/local/lib/python2.7/dist-packages/twisted/python/context.py”,第81行
返回函数(*参数,**kw)
文件“testaccess.py”,第9行,在get\n\u users中
返回session.query(用户).limit(n).all()
文件“/usr/lib/python2.7/contextlib.py”,第24行,在__
self.gen.next()
文件“/home/louis/Documents/Python/knacki/knacki/db.py”,第36行,在事务上下文中
session.remove()
exceptions.AttributeError:“Session”对象没有属性“remove”
我一点也没想到会这样。我错过了什么?我没有正确地实例化我的作用域_会话
编辑:是有关将此设置与Twisted集成的相关问题。这可能有助于澄清我想要实现的目标。简短回答 在
会话
上调用.remove()
,而不是会话
长答案:
scoped_session
不会真正返回session
类。相反,它创建一个对象,该对象关注调用它的线程。调用它将返回与该线程关联的现有会话
实例,或者关联一个新实例并返回该实例。是将线程与会话相关联的对象
scoped_session
对象上的remove
方法删除当前与调用它的线程关联的session对象。这意味着它与作用域会话相反。调用是一种令人困惑的API
下面是一个简短的Python脚本来说明该行为
import threading
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
_engine = create_engine('sqlite:///:memory:')
Session = scoped_session(sessionmaker(_engine))
def scoped_session_demo(remove=False):
ids = []
def push_ids():
thread_name = threading.currentThread().getName()
data = [thread_name]
data.append(Session())
if remove:
Session.remove()
data.append(Session())
ids.append(data)
t = threading.Thread(target=push_ids)
t.start()
t.join()
push_ids()
sub_thread, main_thread = ids
sub_name, sub_session_a, sub_session_b = sub_thread
main_name, main_session_a, main_session_b = main_thread
print sub_name, sub_session_a == sub_session_b
print main_name, main_session_a == main_session_b
print sub_name, '==', main_name, sub_session_a == main_session_b
print 'Without remove:'
scoped_session_demo()
print 'With remove:'
scoped_session_demo(True)
其产出:
Without remove:
Thread-1 True
MainThread True
Thread-1 == MainThread False
With remove:
Thread-2 False
MainThread False
Thread-2 == MainThread False
@马克·威廉姆斯,成功了!认可的!非常感谢你!如果我采用这种方法,我是否需要关心我自己的急切加载?我也犯了同样的错误,我偶然发现了这篇文章。在文档中,它明确提到要使用“scoped_session.remove()”,后面说的是session.remove()。使用哪一个是相当混乱的。看见