Python 在SQLAlchemy中查询添加到未提交会话的对象
所以我在没有太多背景的情况下提出了这个问题,结果被否决了,让我们再试一次 首先,我没有遵循SQLAlchemy的Python 在SQLAlchemy中查询添加到未提交会话的对象,python,transactions,sqlalchemy,Python,Transactions,Sqlalchemy,所以我在没有太多背景的情况下提出了这个问题,结果被否决了,让我们再试一次 首先,我没有遵循SQLAlchemy的会话.add的逻辑。我知道它将对象排队等待插入,我也知道session.query在连接的数据库中而不是在会话中查找,但是在SQLAlchemy中,是否有可能在不首先执行session.flush的情况下查询会话?我对session.query的期望是它查询session.query 我现在正在手动查看会话。在会话中出现无后新建。query().first() 我不想执行会话的原因有
会话.add的逻辑。我知道它将对象排队等待插入,我也知道session.query
在连接的数据库中而不是在会话中查找,但是在SQLAlchemy中,是否有可能在不首先执行session.flush
的情况下查询会话?我对session.query的期望是它查询session.query
我现在正在手动查看会话。在会话中出现无
后新建。query().first()
我不想执行会话的原因有两个。在执行会话之前刷新。查询
- 一个是基于效率的担忧(如果我仍在用户可能希望回滚的会话中,为什么我要写入数据库并查询数据库?)李>
- 第二个原因是我采用了一个,它设法定义了自己的
会话
,其实例导致flush也提交
所以这个问题的核心是谁在帮助我在github上发现GPL程序中的错误
这是一段代码片段,在bauble/ghini中有一个令人惊讶的行为:
# setting up things in ghini
# <replace-later>
import bauble
import bauble.db as db
db.open('sqlite:///:memory:', verify=False)
from bauble.prefs import prefs
import bauble.pluginmgr as pluginmgr
prefs.init()
prefs.testing = True
pluginmgr.load()
db.create(True)
Session = bauble.db.Session
from bauble.plugins.garden import Location
# </replace-later>
# now just plain straightforward usage
session = Session()
session.query(Location).delete()
session.commit()
u0 = session.query(Location).filter_by(code=u'mario').first()
print u0
u1 = Location(code=u'mario')
session.add(u1)
session.flush()
u2 = session.query(Location).filter_by(code=u'mario').one()
print u1, u2, u1==u2
session.rollback()
u3 = session.query(Location).filter_by(code=u'mario').first()
print u3
这里有我认为只是建立数据库的标准简单代码:
from sqlalchemy import Column, Unicode
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Location(Base):
__tablename__ = 'location'
code = Column(Unicode(64), index=True, primary_key=True)
def __init__(self, code=None):
self.code = code
def __repr__(self):
return self.code
from sqlalchemy import create_engine
engine = create_engine('sqlite:///joindemo.db')
Base.metadata.create_all(engine)
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine, autoflush=False)
这样,上述相同代码片段的输出就不那么令人惊讶了:
None
mario mario True
None
bauble中的刷新最终发出提交的原因是它们处理历史记录表的位置:
table.insert(dict(table_name=mapper.local_table.name,
table_id=instance.id, values=str(row),
operation=operation, user=user,
timestamp=datetime.datetime.today())).execute()
它们不使用传入的事务连接在事件处理程序中发出额外的SQL,而是按原样执行语句本身,这意味着它最终使用引擎作为绑定(通过表的元数据找到)。使用引擎执行具有以下行为。由于a,每个线程只有一个连接,因此该语句最终也会提交刷新的更改。我想知道这个错误是否是bauble禁用
修复方法是将事件处理更改为使用事务连接:
class HistoryExtension(orm.MapperExtension):
"""
HistoryExtension is a
:class:`~sqlalchemy.orm.interfaces.MapperExtension` that is added
to all clases that inherit from bauble.db.Base so that all
inserts, updates, and deletes made to the mapped objects are
recorded in the `history` table.
"""
def _add(self, operation, mapper, connection, instance):
"""
Add a new entry to the history table.
"""
... # a ton of code here
table = History.__table__
stmt = table.insert(dict(table_name=mapper.local_table.name,
table_id=instance.id, values=str(row),
operation=operation, user=user,
timestamp=datetime.datetime.today()))
connection.execute(stmt)
def after_update(self, mapper, connection, instance):
self._add('update', mapper, connection, instance)
def after_insert(self, mapper, connection, instance):
self._add('insert', mapper, connection, instance)
def after_delete(self, mapper, connection, instance):
self._add('delete', mapper, connection, instance)
值得注意的是,自0.7版以来,它一直被弃用
关于你对我引用的会议的看法,你确实应该仔细阅读:
从最一般的意义上讲,会话
建立了与数据库的所有对话,并为您在其生命周期内加载或关联的所有对象表示一个“保留区”。它提供入口点以获取查询
对象,该对象使用会话
对象的当前数据库连接将查询发送到数据库
以及:
Yeee…不是。它在某种程度上被用作缓存,因为它实现了身份映射模式,并存储键控到主键的对象。但是,它不做任何类型的查询缓存。这意味着,如果你说session.query(Foo).filter\u by(name='bar')
,即使Foo(name='bar')
就在那里,在身份映射中,会话对此一无所知。它必须向数据库发出SQL,取回行,然后当它看到行中的主键时,它可以在本地标识映射中查看对象是否已经存在。只有当您说query.get({some primary key})
时,会话才不必发出查询
因此:
我对session.query的期望是它查询会话
你的期望是错误的。会话
处理与数据库之间的对话
我不想在session.query之前执行session.flush有两个原因
- 一个是基于效率的担忧(如果我仍在用户可能希望回滚的会话中,为什么我要写入数据库并查询数据库?)李>
因为您的数据库可能会进行验证,具有触发器,并为某些列生成值—主键、时间戳等。您认为要插入的数据可能会在数据库中出现其他内容,会话
完全无法知道这一点
另外,为什么SQLAlchemy应该在自己的内存中实现一种DB,使用自己的查询引擎,以及同步2个数据库所带来的所有问题?SQLAlchemy如何支持您查询的不同数据库的所有不同操作和功能?您的简单等式谓词示例只触及了表面
回滚时,回滚DB的事务(以及会话的未刷新更改)
- 第二个原因是我采用了一个相当大的程序,它能够定义自己的会话,其实例也会导致flush提交
由事件处理错误引起。您已禁用,因此您的mario,none,False
工作正常。将对数据库触发查询,如果您没有手动或自动将会话中保留的更改刷新到数据库,则查询无法看到这些更改。而flush并不意味着提交,所以有其他事情发生了,您应该提供一个关于这一点的示例,或者更清楚地说明“回滚无效”的含义。我禁用了autoflush,因为正如您所提到的,我试图生成一个最小的示例,从,单元测试依赖于禁用自动刷新。»刷新并不意味着提交,因此出现了其他问题«,我试图在ghini.desktop代码中查找它,但我不认识它。而且这个代码远远不是最小的。»对DB启动一个查询«-因为query
是会话的一个方法,我假设我是在查询会话,所以我很惊讶session.query
在session中不返回对象
class HistoryExtension(orm.MapperExtension):
"""
HistoryExtension is a
:class:`~sqlalchemy.orm.interfaces.MapperExtension` that is added
to all clases that inherit from bauble.db.Base so that all
inserts, updates, and deletes made to the mapped objects are
recorded in the `history` table.
"""
def _add(self, operation, mapper, connection, instance):
"""
Add a new entry to the history table.
"""
... # a ton of code here
table = History.__table__
stmt = table.insert(dict(table_name=mapper.local_table.name,
table_id=instance.id, values=str(row),
operation=operation, user=user,
timestamp=datetime.datetime.today()))
connection.execute(stmt)
def after_update(self, mapper, connection, instance):
self._add('update', mapper, connection, instance)
def after_insert(self, mapper, connection, instance):
self._add('insert', mapper, connection, instance)
def after_delete(self, mapper, connection, instance):
self._add('delete', mapper, connection, instance)