【问题标题】:How use transaction in sql alchemy while using db session?使用 db session 时如何在 sql alchemy 中使用事务?
【发布时间】:2012-04-21 05:49:41
【问题描述】:

我在我的项目中使用 sql alchemy,我使用了 db session,

engine = create_engine(configuration)
db_session = scoped_session(sessionmaker(autocommit=False,
                                     autoflush=False,
                                     bind=engine))

Base = declarative_base()
Base.query = db_session.query_property()

def init_db():    
    import models
    Base.metadata.create_all(bind=engine)

数据库会话用作:

db_session.merge(order)      #order(model) in object
db_session.commit()

现在我想将数据插入两个表订单和订单行项目,所以我需要事务, 作为: 1. 在第一次插入中,我希望插入订单的 id 在第二次插入查询中使用 2. 如果第二个插入查询失败,那么第一个查询应该回滚

Try:
    #begin transaction/How to begin transaction?
    order=db_session.add(order)      #insert into order
    #is need to commit db_session here as I need inserted orders id
    #here actually db_session.commit() needed to get order's id(auto generated) 
    #if db_session committed here then sql alchemy starts new session       

    order_line_item.id = order.id
    db_session.add(order_line_item)    #insert into order line line item

    db_session.commit()
    #check transaction status if failed then rollback, How to check status?

except:
    db_session.rollback()

如何使用交易?

【问题讨论】:

    标签: transactions sqlalchemy


    【解决方案1】:

    你必须给用户nested transaction点赞

    top_trans = connection.begin()
    try:
        #begin transaction/How to begin transaction?
        order_trans = connection.begin()
        order=db_session.add(order)      #insert into order
        order_trans.commit()
    
        order_line_item.id = order.id
        order_line_trans = connection.begin()
        db_session.add(order_line_item)    #insert into order line line item
    
        order_line_trans.commit()
        #check transaction status if failed then rollback, How to check status?
    
    except:
        top_trans.rollback()
    

    您也可以使用two phase 交易。两者各有优势,哪一款适合你,你可以使用

    【讨论】:

      【解决方案2】:

      Lafada 建议的嵌套事务不适用于这种情况。 flush() 就可以了,例如

      db_session.begin()
      try:
          db_session.add(order)
      
          db_session.flush()
      
          order_line_item.id = order.id
          db_session.add(order_line_item)
      
          db_session.commit()
      except:
          db_session.rollback()
      

      或者更好的是,如果您在订单和订单项之间正确设置了关系,您甚至不应该费心手动分配 id。

      【讨论】:

      • 我会使用with db_session.begin():...,如果可能,删除try: ... except:...,因为它隐藏了所有异常。
      • flush 也不是有意的。看看我的回答应该怎么做!
      【解决方案3】:

      你应该使用 SQLAlchemy 的relationship 特性,所以你不要 必须搞乱外键。因此,例如您的订单商品可以 看起来像(我假设你有一个多对一的关系):

      class OrderLineItem(Base):
          id = Column(Integer, primary_key=True)
          order_id = Column(Integer, ForeignKey('orders.id'))
          order = relationship('Order', backref='order_line_items')
      

      在插入时,您只需分配订单实例:

      order_line_item.order = order
      session.add(order)  # you even don't have to insert the item!
      

      在教程中查看更多详细信息:http://docs.sqlalchemy.org/en/latest/orm/relationships.html

      【讨论】:

        猜你喜欢
        • 2016-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-11
        • 2011-03-01
        相关资源
        最近更新 更多