SQLAlchemy: motor, conexión y diferencia de sesión

Resuelto ololobus asked hace 8 años • 3 respuestas

Utilizo SQLAlchemy y hay al menos tres entidades: y engine, que tienen método, por lo que si, por ejemplo, quiero seleccionar todos los registros, puedo hacerlo en el nivel del motor :sessionconnectionexecutetable

engine.execute(select([table])).fetchall()

y en el nivel de Conexión :

connection.execute(select([table])).fetchall()

e incluso en el nivel de sesión :

session.execute(select([table])).fetchall()

- los resultados serán los mismos.

Según tengo entendido, si alguien engine.executelo usa, crea connection, abre session(Alchemy se encarga de ello por usted) y ejecuta la consulta. Pero, ¿existe una diferencia global entre estas tres formas de realizar tal tarea?

ololobus avatar Dec 17 '15 04:12 ololobus
Aceptado

Ejecutando .execute()

Al ejecutar un planoSELECT * FROM tablename , no hay diferencia en el resultado proporcionado.

Las diferencias entre estos tres objetos se vuelven importantes dependiendo del contexto en el que SELECTse usa la declaración o, más comúnmente, cuando quieres hacer otras cosas como INSERT,DELETE etc.

Cuándo usar Engine, Connection, Session en general

  • Engine es el objeto de nivel más bajo utilizado por SQLAlchemy. Mantiene un grupo de conexiones disponibles para su uso siempre que la aplicación necesite comunicarse con la base de datos. .execute()Es un método conveniente que llama primero conn = engine.connect(close_with_result=True)y luego conn.execute(). El parámetro close_with_result significa que la conexión se cierra automáticamente. (Estoy parafraseando ligeramente el código fuente, pero es esencialmente cierto). editar: Aquí está el código fuente de Engine.execute

    Puede utilizar el motor para ejecutar SQL sin formato.

      result = engine.execute('SELECT * FROM tablename;')
      # what engine.execute() is doing under the hood:
      conn = engine.connect(close_with_result=True)
      result = conn.execute('SELECT * FROM tablename;')
    
      # after you iterate over the results, the result and connection get closed
      for row in result:
          print(result['columnname']
    
      # or you can explicitly close the result, which also closes the connection
      result.close()
    

    Esto se trata en los documentos bajo uso básico .

  • La conexión es (como vimos arriba) lo que realmente hace el trabajo de ejecutar una consulta SQL. Debe hacer esto siempre que desee un mayor control sobre los atributos de la conexión, cuándo se cierra, etc. Un ejemplo importante de esto es una transacción , que le permite decidir cuándo enviar sus cambios a la base de datos (si es que los hace). En uso normal, los cambios se confirman automáticamente. Con el uso de transacciones, podría (por ejemplo) ejecutar varias sentencias SQL diferentes y, si algo sale mal con una de ellas, podría deshacer todos los cambios a la vez.

      connection = engine.connect()
      trans = connection.begin()
      try:
          connection.execute(text("INSERT INTO films VALUES ('Comedy', '82 minutes');"))
          connection.execute(text("INSERT INTO datalog VALUES ('added a comedy');"))
          trans.commit()
      except Exception:
          trans.rollback()
          raise
    

    Esto le permitiría deshacer ambos cambios si uno falla, como si olvidara crear la tabla de registro de datos.

    Entonces, si está ejecutando código SQL sin formato y necesita control, use conexiones

  • Las sesiones se utilizan para el aspecto de gestión de relaciones entre objetos (ORM) de SQLAlchemy (de hecho, puede ver esto en cómo se importan:) from sqlalchemy.orm import sessionmaker. Utilizan conexiones y transacciones internas para ejecutar sus declaraciones SQL generadas automáticamente..execute()es una función de conveniencia que pasa a cualquier cosa a la que esté vinculada la sesión (generalmente un motor, pero puede ser una conexión).

    Si está utilizando la funcionalidad ORM, utilice una sesión. Si solo realiza consultas SQL directas no vinculadas a objetos, probablemente sea mejor utilizar conexiones directamente.

Neal avatar Mar 13 '2017 20:03 Neal

Una descripción general de una línea:

El comportamiento de execute()es el mismo en todos los casos, pero son 3 métodos diferentes, en Engine, Connectiony Sessionclases.

¿ Qué es exactamente execute()?

Para comprender el comportamiento de execute()necesitamos observar la Executableclase. Executablees una superclase para todos los tipos de objetos de “declaraciones”, incluidos select(), delete(),update(), insert(), text(); en las palabras más simples posibles, es Executableuna construcción de expresión SQL compatible con SQLAlchemy.

En todos los casos, el execute()método toma el texto SQL o la expresión SQL construida, es decir, cualquiera de la variedad de construcciones de expresión SQL admitidas en SQLAlchemy y devuelve los resultados de la consulta (a: ResultProxyenvuelve un DB-APIobjeto de cursor para proporcionar un acceso más fácil a las columnas de fila).


Para aclararlo más (solo para una aclaración conceptual, no es un enfoque recomendado) :

Además de Engine.execute()(ejecución sin conexión), Connection.execute()y Session.execute(), también es posible utilizar execute()directamente en cualquier Executableconstrucción. La Executableclase tiene su propia implementación execute(): según la documentación oficial, una descripción de una línea sobre lo que execute()hace es " Compilar y ejecutar estoExecutable ". En este caso, necesitamos vincular explícitamente la Executable(construcción de expresión SQL) con un Connectionobjeto u Engineobjeto (que implícitamente obtiene un Connectionobjeto), para que execute()sepa dónde ejecutar el archivo SQL.

El siguiente ejemplo lo demuestra bien: dada la siguiente tabla:

from sqlalchemy import MetaData, Table, Column, Integer

meta = MetaData()
users_table = Table('users', meta,
    Column('id', Integer, primary_key=True),
    Column('name', String(50)))

Ejecución explícita , es decir Connection.execute(), pasar el texto SQL o la expresión SQL construida al execute()método de Connection:

engine = create_engine('sqlite:///file.db')
connection = engine.connect()
result = connection.execute(users_table.select())
for row in result:
    # ....
connection.close()

Ejecución explícita sin conexión , es decir Engine.execute(), pasar el texto SQL o la expresión SQL construida directamente al execute()método del motor:

engine = create_engine('sqlite:///file.db')
result = engine.execute(users_table.select())
for row in result:
    # ....
result.close()

La ejecución implícita , Executable.execute()es decir, también es sin conexión y llama al execute()método de Executable, es decir, llama al execute()método directamente en la SQLconstrucción de expresión (una instancia de Executable).

engine = create_engine('sqlite:///file.db')
meta.bind = engine
result = users_table.select().execute()
for row in result:
    # ....
result.close()

Nota: Indicó el ejemplo de ejecución implícita con fines de aclaración (esta forma de ejecución no se recomienda en absoluto) según los documentos :

La “ejecución implícita” es un patrón de uso muy antiguo que en la mayoría de los casos es más confuso que útil, y se desaconseja su uso. Ambos patrones parecen fomentar el uso excesivo de “atajos” convenientes en el diseño de aplicaciones, lo que conduce a problemas posteriores.


Tus preguntas:

Según tengo entendido, si alguien usa Engine.execute, crea una conexión, abre la sesión (Alchemy se preocupa por usted) y ejecuta la consulta.

Tienes razón en la parte "si alguien engine.executelo usa crea connection", pero no en "abre session(Alchemy se preocupa por ti) y ejecuta la consulta". Usar Engine.execute()y Connection.execute()es (casi) lo mismo, en formal, Connectionel objeto se crea implícitamente. , y en el caso posterior lo creamos explícitamente. Lo que realmente sucede en este caso es:

`Engine` object (instantiated via `create_engine()`) -> `Connection` object (instantiated via `engine_instance.connect()`) -> `connection.execute({*SQL expression*})`

Pero, ¿existe una diferencia global entre estas tres formas de realizar dicha tarea?

En la capa de base de datos es exactamente lo mismo, todos ejecutan SQL (expresión de texto o varias construcciones de expresión SQL). Desde el punto de vista de la aplicación existen dos opciones:

  • Ejecución directa: utilizando Engine.execute()oConnection.execute()
  • Usando - maneja eficientemente la transacción como una sessionssola unidad de trabajo, con facilidad a través de session.add(), session.rollback(), session.commit(). session.close()Es la forma de interactuar con la base de datos en el caso de ORM, es decir, tablas asignadas. Proporciona identidad_map para obtener instantáneamente objetos ya accedidos o recién creados/agregados durante una sola solicitud.

Session.execute()En última instancia, utiliza Connection.execute()el método de ejecución de declaraciones para ejecutar la declaración SQL. El uso Sessionde objetos es la forma recomendada por SQLAlchemy ORM para que una aplicación interactúe con la base de datos.

Un extracto de los documentos :

Es importante tener en cuenta que cuando se utiliza SQLAlchemy ORM, generalmente no se accede a estos objetos; en su lugar, el objeto Session se utiliza como interfaz para la base de datos. Sin embargo, para las aplicaciones que se basan en el uso directo de sentencias SQL textuales y/o construcciones de expresiones SQL sin la participación de los servicios de administración de nivel superior del ORM, el motor y la conexión son el rey (¿y la reina?); siga leyendo.

Nabeel Ahmed avatar Dec 18 '2015 21:12 Nabeel Ahmed