Python >> Tutorial de Python >  >> Python

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

Una descripción general de una línea:

El comportamiento de execute() es igual en todos los casos, pero son 3 métodos diferentes, en Engine , Connection y Session clases.

¿Qué es exactamente execute()? :

Para comprender el comportamiento de execute() tenemos que mirar en el Executable clase. Executable es una superclase para todos los tipos de objetos de "declaración", incluidos select(), delete(), update(), insert(), text() - en las palabras más simples posibles, un Executable es una construcción de expresión SQL compatible con SQLAlchemy.

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

Para aclararlo más (solo para 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 el execute() directamente en cualquier Executable construir. El Executable la clase tiene su propia implementación de execute() - Según la documentación oficial, una descripción de una línea sobre lo que execute() hace es "Compilar y ejecutar este Executable ". En este caso, necesitamos vincular explícitamente el Executable (construcción de expresión SQL) con un Connection objeto o, Engine objeto (que implícitamente obtiene un Connection objeto), por lo que el execute() sabrá dónde ejecutar el SQL .

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

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 de Motor:

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

Ejecución implícita es decir, Executable.execute() - también es sin conexión y llama al execute() método del Executable , es decir, llama a execute() método directamente en el SQL construcción de expresión (una instancia de Executable ) en sí mismo.

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

Nota:Indiqué el ejemplo de ejecución implícita con el fin de aclarar, esta forma de ejecución no es muy recomendable, 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 alentar el uso excesivo de "atajos" convenientes en el diseño de la aplicación, lo que conduce a problemas más adelante.

Tus preguntas:

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

Tienes razón para la parte "si alguien usa engine.execute crea connection " pero no para "abre session (Alchemy se preocupa por ti) y ejecuta la consulta " - Usando Engine.execute() y Connection.execute() es (casi) lo mismo, formalmente, Connection el objeto se crea implícitamente y, en un caso posterior, lo instanciamos 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 tal tarea?

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

  • Ejecución directa - Usando Engine.execute() o Connection.execute()
  • Usando sessions - maneja eficientemente la transacción como una sola 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 mapeadas. Proporciona un mapa de identidad para obtener instantáneamente objetos ya accedidos o recién creados/agregados durante una sola solicitud.

Session.execute() finalmente usa Connection.execute() método de ejecución de sentencia para ejecutar la sentencia SQL. Usando Session object 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 usa 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 crean en torno al uso directo de sentencias SQL textuales y/o construcciones de expresiones SQL sin la participación de los servicios de gestión de nivel superior de ORM, el motor y la conexión son los reyes (¿y la reina?), siga leyendo.


La respuesta de Nabeel cubre muchos detalles y es útil, pero me resultó confuso seguirla. Dado que este es actualmente el primer resultado de Google para este problema, agrego mi comprensión para futuras personas que encuentren esta pregunta:

Ejecutando .execute()

Como OP y Nabell Ahmed señalan, al ejecutar un SELECT * FROM tablename simple , no hay diferencia en el resultado proporcionado.

Las diferencias entre estos tres objetos se vuelven importantes según el contexto en el que SELECT se usa en o, más comúnmente, cuando quiere hacer otras cosas como INSERT , DELETE , etc

Cuándo usar Motor, Conexión, Sesión en general

  • Motor es el objeto de nivel más bajo utilizado por SQLAlchemy. Mantiene un conjunto 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 primero llama a 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 esencialmente cierto). editar:Aquí está el código fuente de engine.execute

    Puede usar 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 está cubierto en los documentos bajo uso básico.

  • 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. Por ejemplo, un ejemplo muy importante de esto es una Transacción, que le permite decidir cuándo enviar sus cambios a la base de datos. En uso normal, los cambios se confirman automáticamente. Con el uso de transacciones, podría (por ejemplo) ejecutar varias instrucciones 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("INSERT INTO films VALUES ('Comedy', '82 minutes');")
        connection.execute("INSERT INTO datalog VALUES ('added a comedy');")
        trans.commit()
    except:
        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 procesar y necesita control, use conexiones

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

    Si está usando la funcionalidad ORM, use sesión; si solo está realizando consultas SQL directas no vinculadas a objetos, probablemente sea mejor que use las conexiones directamente.