2010-11-17 20 views
273

¿Cuál es la diferencia entre flush() y commit() en SQLAlchemy?SQLAlchemy: ¿Cuál es la diferencia entre flush() y commit()?

He leído los documentos, pero no soy más prudente: parecen asumir una comprensión previa que yo no tengo.

Estoy particularmente interesado en su impacto en el uso de la memoria. Estoy cargando algunos datos en una base de datos a partir de una serie de archivos (alrededor de 5 millones de filas en total) y mi sesión a veces se cae: es una gran base de datos y una máquina con poca memoria.

Me pregunto si estoy usando demasiadas commit() y no suficientes llamadas flush(), pero sin realmente entender cuál es la diferencia, es difícil de decir.

Respuesta

334

Un objeto Session es básicamente una transacción en curso de cambios en una base de datos (actualización, inserción, eliminación). Estas operaciones no se conservan en la base de datos hasta que no se hayan confirmado (si el programa aborta por alguna razón en una transacción de mitad de sesión, se pierden todos los cambios no comprometidos).

El objeto de sesión registra las operaciones de transacción con session.add(), pero aún no las comunica a la base de datos hasta que se llama al session.flush().

session.flush() comunica una serie de operaciones a la base de datos (insertar, actualizar, eliminar). La base de datos los mantiene como operaciones pendientes en una transacción. Los cambios no se conservan permanentemente en el disco ni son visibles para otras transacciones hasta que la base de datos recibe un COMPROMISO para la transacción actual (que es lo que hace session.commit()).

session.commit() confirma (persiste) esos cambios en la base de datos.

flush() es siempre llamado como parte de una llamada a commit() (1).

Cuando utiliza un objeto Session para consultar la base de datos, la consulta arrojará resultados tanto de la base de datos como de las partes lavadas de la transacción no confirmada que contiene. De forma predeterminada, Session objeta autoflush sus operaciones, pero esto se puede deshabilitar.

Esperamos que este ejemplo se hacer esto más claro:

#--- 
s = Session() 

s.add(Foo('A')) # The Foo('A') object has been added to the session. 
       # It has not been committed to the database yet, 
       # but is returned as part of a query. 
print 1, s.query(Foo).all() 
s.commit() 

#--- 
s2 = Session() 
s2.autoflush = False 

s2.add(Foo('B')) 
print 2, s2.query(Foo).all() # The Foo('B') object is *not* returned 
          # as part of this query because it hasn't 
          # been flushed yet. 
s2.flush()     # Now, Foo('B') is in the same state as 
          # Foo('A') was above. 
print 3, s2.query(Foo).all() 
s2.rollback()    # Foo('B') has not been committed, and rolling 
          # back the session's transaction removes it 
          # from the session. 
print 4, s2.query(Foo).all() 

#--- 
Output: 
1 [<Foo('A')>] 
2 [<Foo('A')>] 
3 [<Foo('A')>, <Foo('B')>] 
4 [<Foo('A')>] 
+0

Una cosa más: ¿sabes si llamar a commit() aumenta la memoria utilizada o la reduce? – AP257

+2

Esto también es falso para motores db que no admiten transacciones como myisam. Como no hay una transacción en curso, el color tiene aún menos para distinguirse del compromiso. – underrun

+0

@underrun Entonces, si hago 'session.query()' después de 'session.flush()', ¿veré mis cambios? Dado que estoy usando MyISAM. –

9

Como dice @snapshoe

flush() envía las sentencias SQL a la base de datos

commit() confirma la transacción.

Cuando session.autocommit == Falso:

commit() llamará a flush() si su autoflush == true.

Cuando la sesión.confirmación automática == true:

no puede llamar a commit() si no se ha iniciado una transacción (que es probable que no tiene ya que probablemente sólo se utilizaría este modo para evitar la administración manual de transacciones).

En este modo, debe llamar a flush() para guardar sus cambios de ORM. La descarga efectivamente también compromete sus datos.

Cuestiones relacionadas