2012-04-08 7 views
9

estoy usando la alquimia sql en mi proyecto, he utilizado sesión db,¿Cómo se usa la transacción en sql alquimia durante el uso de la sesión de db?

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) 

sesión de base de datos utilizado como:

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

Ahora quiero insertar datos en dos tablas de pedido o la línea orden , por lo que necesito transacción, como: Identificación de fin 1. en primer inserto deseo que se inserte a utilizar en la segunda consulta de inserción 2. Si la segunda consulta de inserción fracasaron luego la primera consulta debe Rollback

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() 

¿Cómo utilizar la trasacción?

Respuesta

15

La transacción anidada, como lo sugiere Lafada, no está diseñada para tal situación. A flush() le irá bien, p.

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() 

O mejor aún, si se ha configurado correctamente la relación entre el pedido y la línea, no debe molestarse para asignar ID manualmente.

+3

Yo usaría 'con db_session.begin(): ...' y, si fuera posible, eliminaría 'try: ... excepto: ...' ya que oculta todas las excepciones. – Governa

+0

'flush' no está destinado, también. ¡Vea mi respuesta cómo debería hacerse! – schlamar

1

Tienes que nested transaction usuario como

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() 

También puede utilizar two phase transacción. Ambos tienen la ventaja de que uno es adecuado para usted y puede usar

5

Debe utilizar la característica relationship de SQLAlchemy, para que no tenga que perder el tiempo con las claves externas. Así, por ejemplo, su posición de pedido podría parecerse a (I suponga que tiene un muchos-uno):

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

Y en el inserto que acaba de asignar la instancia orden:

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

Ver más detalles en el tutorial: http://docs.sqlalchemy.org/en/latest/orm/relationships.html

Cuestiones relacionadas