Solución:
Un objeto de sesión es básicamente una transacción en curso de cambios en una base de datos (actualizar, insertar, eliminar). Estas operaciones no se conservan en la base de datos hasta que se confirman (si su programa se cancela por algún motivo en la transacción a mitad de sesión, se perderán los cambios no confirmados).
El objeto de sesión registra las operaciones de transacción con session.add()
, pero aún no los comunica a la base de datos hasta session.flush()
se llama.
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 mantienen permanentemente en el disco, ni son visibles para otras transacciones hasta que la base de datos recibe un COMMIT para la transacción actual (que es lo que session.commit()
lo hace).
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 devolverá resultados tanto de la base de datos como de las partes vacías de la transacción no confirmada que contiene. De forma predeterminada, los objetos de sesión autoflush
sus operaciones, pero esto puede desactivarse.
Con suerte, este ejemplo lo aclarará más:
#---
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')>]
Como dice @snapshoe
flush()
envía sus declaraciones SQL a la base de datos
commit()
confirma la transacción.
Cuando session.autocommit == False
:
commit()
llamará flush()
si te pones autoflush == True
.
Cuando session.autocommit == True
:
No puedes llamar commit()
si no ha iniciado una transacción (lo que probablemente no haya hecho ya que probablemente solo usaría este modo para evitar la gestión manual de transacciones).
En este modo, debe llamar flush()
para guardar sus cambios de ORM. La descarga también compromete sus datos de manera efectiva.
¿Por qué tirar el agua si puedes comprometerte?
Como alguien nuevo en el trabajo con bases de datos y sqlalchemy, las respuestas anteriores: que flush()
envía sentencias SQL a la base de datos y commit()
los persiste – no me quedaron claros. Las definiciones tienen sentido, pero no está claro de inmediato a partir de las definiciones por qué usaría un flush en lugar de solo comprometerse.
Dado que una confirmación siempre se descarga (https://docs.sqlalchemy.org/en/13/orm/session_basics.html#committing), estos suenan muy similares. Creo que el gran problema a destacar es que una descarga no es permanente y se puede deshacer, mientras que una confirmación es permanente, en el sentido de que no se puede pedir a la base de datos que deshaga la última confirmación (creo)
@snapshoe destaca que si desea consultar la base de datos y obtener resultados que incluyan objetos recién agregados, primero debe eliminarlos (o confirmarlos, lo que se eliminará por usted). Quizás esto sea útil para algunas personas, aunque no estoy seguro de por qué querría flush en lugar de cometer (aparte de la respuesta trivial de que se puede deshacer).
En otro ejemplo, estaba sincronizando documentos entre una base de datos local y un servidor remoto, y si el usuario decidió cancelar, todas las adiciones / actualizaciones / eliminaciones deberían deshacerse (es decir, sin sincronización parcial, solo una sincronización completa). Al actualizar un solo documento, he decidido simplemente eliminar la fila anterior y agregar la versión actualizada desde el servidor remoto. Resulta que debido a la forma en que se escribe sqlalchemy, no se garantiza el orden de las operaciones al comprometerse. Esto resultó en agregar una versión duplicada (antes de intentar eliminar la anterior), lo que resultó en que la base de datos fallara en una restricción única. Para evitar esto, usé flush()
de modo que ese orden se mantuvo, pero aún podía deshacerlo si más tarde fallaba el proceso de sincronización.
Vea mi publicación sobre esto en: ¿Hay algún orden para agregar o eliminar al comprometerse en sqlalchemy?
Del mismo modo, alguien quería saber si agregar orden se mantiene al confirmar, es decir, si agrego object1
Luego añade object2
, lo hace object1
ser agregado a la base de datos antes object2
¿SQLAlchemy guarda el orden al agregar objetos a la sesión?
Nuevamente, aquí presumiblemente el uso de flush () aseguraría el comportamiento deseado. Entonces, en resumen, un uso para flush es proporcionar garantías de orden (creo), nuevamente mientras se permite una opción de “deshacer” que la confirmación no proporciona.
Autoflush y Autocommit
Tenga en cuenta que el autoflush se puede utilizar para garantizar que las consultas actúen en una base de datos actualizada, ya que sqlalchemy se vaciará antes de ejecutar la consulta. https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Session.params.autoflush
Autocommit es otra cosa que no entiendo completamente, pero parece que no se recomienda su uso: https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Session.params. autocommit
Uso de memoria
Ahora, la pregunta original realmente quería saber sobre el impacto de flush vs commit por motivos de memoria. Como la capacidad de persistir o no es algo que ofrece la base de datos (creo), simplemente vaciarlo debería ser suficiente para descargar a la base de datos, aunque comprometerse no debería doler (en realidad probablemente ayude, vea a continuación) si no le importa deshacer .
sqlalchemy usa referencias débiles para objetos que se han vaciado: https://docs.sqlalchemy.org/en/13/orm/session_state_management.html#session-referencing-behavior
Esto significa que si no tiene un objeto retenido explícitamente en algún lugar, como en una lista o dictado, sqlalchemy no lo mantendrá en la memoria.
Sin embargo, entonces tienes que preocuparte del lado de la base de datos. Presumiblemente, vaciar sin comprometerse viene con una penalización de memoria para mantener la transacción. Nuevamente, soy nuevo en esto, pero aquí hay un enlace que parece sugerir exactamente esto: https://stackoverflow.com/a/15305650/764365
En otras palabras, las confirmaciones deberían reducir el uso de la memoria, aunque es de suponer que aquí hay una compensación entre la memoria y el rendimiento. En otras palabras, probablemente no desee realizar todos los cambios en la base de datos, uno a la vez (por razones de rendimiento), pero esperar demasiado aumentará el uso de la memoria.