在循环中使用SQLAlchemy Session对象提交数据时出现问题

时间:2011-09-16 15:49:40

标签: python sqlalchemy

我有一个SQLalchemy的数据库提交问题。这是我的场景我有一个要添加到表中的记录列表。将记录添加到表中后,我需要获取插入的记录Id并在第二个表中执行另一个插入。我在单个会话下进行这些操作。代码结构如下所示,因为我不允许提供代码

创建会话对象

循环要插入的记录列表:

 do the session.add(obj)

 session.commit()

 get obj.id

 do the session.add(obj2) # with obj2 having the id from the obj

 session.commit()

如果我们有多条记录,这里只有最后一条记录数据正确提交

请有人帮我纠正这个问题。

2 个答案:

答案 0 :(得分:8)

很有可能需要发出两次提交;使用sqlalchemy会话的主要原因之一是它了解对象如何相互关联,并将以这样的方式对其插入进行排序,即数据被正确插入并正确表示所需的结构。这主要通过relationship构造工作。这是一个简单的例子:

>>> from sqlalchemy import *
>>> from sqlalchemy.orm import *
>>> from sqlalchemy.ext.declarative import declarative_base
>>> Base = declarative_base()

>>> class A(Base):
...     __tablename__ = "a_table"
...     id = Column(Integer, primary_key=True)
... 
>>> class B(Base):
...     __tablename__ = "b_table"
...     id = Column(Integer, primary_key=True)
...     a_id = Column(Integer, ForeignKey(A.id))
...     a = relationship(A)
... 
>>> my_a = A()
>>> my_b = B()
>>> my_b.a = my_a
>>> 

最重要的部分是我们宣布ABB.a之间的关系。为了充分利用这一点,通过此关系属性表达每个实例之间的关系非常重要,并且让sqlalchemy负责设置a_id列本身。

>>> engine = create_engine("sqlite:///:memory:")
>>> Base.metadata.create_all(engine)
>>> engine.echo = True
>>> Session = sessionmaker(engine)
>>> 
>>> session = Session()
>>> session.add(my_a)
>>> session.add(my_b)
>>> 
>>> session.commit()

使用echo=True,输出看起来有点像这样:

2011-09-16 17:19:22,367 INFO sqlalchemy.engine.base.Engine.0x...ed50 BEGIN (implicit)
2011-09-16 17:19:22,368 INFO sqlalchemy.engine.base.Engine.0x...ed50 INSERT INTO a_table DEFAULT VALUES
2011-09-16 17:19:22,368 INFO sqlalchemy.engine.base.Engine.0x...ed50 ()
2011-09-16 17:19:22,369 INFO sqlalchemy.engine.base.Engine.0x...ed50 INSERT INTO b_table (a_id) VALUES (?)
2011-09-16 17:19:22,369 INFO sqlalchemy.engine.base.Engine.0x...ed50 (1,)
2011-09-16 17:19:22,369 INFO sqlalchemy.engine.base.Engine.0x...ed50 COMMIT

请注意,插入了my_a对象,sqlalchemy读取分配的主键,并将其用于my_b的插入。

答案 1 :(得分:4)

您可以尝试重构代码以使用它:

Session = sqlalchemy.orm.sessionmaker(...)
def transaction(self, callback):
  session = sqlalchemy.orm.scoped_session(Session)
  try:
    result = callback(session)
  except:
    session.rollback()
    raise
  else:
    session.commit()
  finally:
    session.close()
  return result

然后每个事务都有自己的功能,如下所示:

def updatetxn(pk, newvalue):
  def txn(session):
    obj = session.query(myclass).filter_by(id=pk).one()
    obj.field = newvalue
    session.add(obj)
  return txn

transaction(updatetxn(4, 'abc'))

在一个地方处理提交/回滚逻辑,并依靠函数范围来确定工作单​​元的范围,可以降低应用程序的复杂性并消除您尚未发现的错误。