SQLAlchemy: differenza tra motore, connessione e sessione


134

Io uso SQLAlchemy e ci sono almeno tre soggetti: engine, sessione connection, che hanno executeil metodo, quindi se ad esempio si desidera selezionare tutti i record dalla tableposso fare questo

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

e questo

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

e anche questo

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

- i risultati saranno gli stessi.

A quanto ho capito, se qualcuno lo usa engine.executecrea connection, si apre session(Alchemy si prende cura di te per te) ed esegue la query. Ma c'è una differenza globale tra questi tre modi di svolgere un simile compito?


Penso che la tua risposta sia proprio qui: hackersandslackers.com/…
SeF

Risposte:


123

Una panoramica di una riga:

Il comportamento di execute()è uguale in tutti i casi, ma sono 3 metodi differenti, in Engine, Connectione Sessionclassi.

Che cosa è esattamente execute():

Per capire il comportamento di execute()dobbiamo guardare in Executableclasse. Executableè una superclasse per tutti i tipi di oggetti "istruzione", inclusi select (), delete (), update (), insert (), text () - in parole semplici possibili, Executableè un costrutto di espressione SQL supportato in SQLAlchemy.

In tutti i casi il execute()metodo accetta il testo SQL o l'espressione SQL costruita, ovvero una qualsiasi varietà di costrutti di espressioni SQL supportati in SQLAlchemy e restituisce risultati di query (a ResultProxy- Avvolge un DB-APIoggetto cursore per fornire un accesso più facile alle colonne di riga.)


Per chiarire ulteriormente (solo per chiarimenti concettuali, non un approccio raccomandato) :

Oltre a Engine.execute()(esecuzione senza connessione), Connection.execute()e Session.execute(), è anche possibile usare il execute()direttamente su qualsiasi Executablecostrutto. La Executableclasse ha la propria implementazione di execute()- Secondo la documentazione ufficiale, una riga di descrizione di ciò che execute()fa è " Compila ed esegui questoExecutable ". In questo caso dobbiamo associare esplicitamente il Executable(costrutto dell'espressione SQL) con un Connectionoggetto o un Engineoggetto (che ottiene implicitamente un Connectionoggetto), quindi execute()sapremo dove eseguire il SQL.

L'esempio seguente lo dimostra bene - Data una tabella come di seguito:

from sqlalchemy import MetaData, Table, Column, Integer

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

Esecuzione esplicita, vale a dire Connection.execute()- passaggio del testo SQL o dell'espressione SQL costruita al execute()metodo di Connection:

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

Esecuzione esplicita senza connessione ovvero Engine.execute()- passaggio del testo SQL o dell'espressione SQL costruita direttamente al execute()metodo di Engine:

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

L'esecuzione implicita, cioè Executable.execute()- è anche senza connessione e chiama ilexecute() metodo del Executable, cioè chiama il execute()metodo direttamente sul SQLcostrutto dell'espressione (un'istanza di Executable) stessa.

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

Nota: indicato l'esempio di esecuzione implicita a scopo di chiarimento - questo metodo di esecuzione è altamente sconsigliato - come da documenti :

"Esecuzione implicita" è un modello di utilizzo molto vecchio che nella maggior parte dei casi è più confuso di quanto sia utile e il suo utilizzo è scoraggiato. Entrambi i modelli sembrano incoraggiare l'uso eccessivo di "scorciatoie" opportune nella progettazione dell'applicazione che portano a problemi in seguito.


Le tue domande:

Come capisco se qualcuno usa engine.execute, crea una connessione, apre una sessione (Alchemy si preoccupa per te) ed esegue la query.

Hai ragione per la parte "se qualcuno lo usa engine.executecrea connection" ma non per "si apre session(Alchemy si prende cura di te per te) ed esegue la query" - Usare Engine.execute()ed Connection.execute()è (quasi) la stessa cosa, in formale, l' Connectionoggetto viene creato implicitamente e in un secondo momento lo istanziamo esplicitamente. Quello che succede davvero in questo caso è:

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

Ma c'è una differenza globale tra questi tre modi di svolgere tale compito?

A livello di DB è esattamente la stessa cosa, tutti eseguono SQL (espressione di testo o vari costrutti di espressioni SQL). Dal punto di vista dell'applicazione ci sono due opzioni:

  • Esecuzione diretta: utilizzando Engine.execute()oConnection.execute()
  • Usando sessions- gestisce in modo efficace operazione come singola unità-di-lavoro, con facilità via session.add(), session.rollback(), session.commit(), session.close(). È il modo di interagire con il DB in caso di ORM, ovvero tabelle mappate. Fornisce identity_map per ottenere immediatamente l'accesso o gli oggetti appena creati / aggiunti durante una singola richiesta.

Session.execute()utilizza infine il Connection.execute()metodo di esecuzione dell'istruzione per eseguire l'istruzione SQL. L'uso Sessiondell'oggetto è il modo consigliato da SQLAlchemy ORM per consentire a un'applicazione di interagire con il database.

Un estratto dai documenti :

È importante notare che quando si utilizza SQLAlchemy ORM, questi oggetti non sono generalmente accessibili; invece, l'oggetto Session viene utilizzato come interfaccia per il database. Tuttavia, per le applicazioni basate sull'utilizzo diretto di istruzioni testuali SQL e / o costrutti di espressioni SQL senza il coinvolgimento dei servizi di gestione di livello superiore dell'ORM, Engine e Connection sono re (e regina?) - continua a leggere.


La parola "senza connessione" implica che non viene creata alcuna connessione, cosa che secondo la risposta di Neal non è il caso.
Atom

111

La risposta di Nabeel copre molti dettagli ed è utile, ma ho trovato confuso da seguire. Poiché questo è attualmente il primo risultato di Google per questo problema, aggiungo la mia comprensione per le persone future che trovano questa domanda:

Esecuzione di .execute ()

Come OP e Nabell Ahmed notano entrambi, quando si esegue una pianura SELECT * FROM tablename, non c'è differenza nel risultato fornito.

Le differenze tra questi tre oggetti diventano importanti a seconda del contesto in cui SELECTviene utilizzata l' istruzione o, più comunemente, quando si desidera fare altre cose come INSERT,DELETE ecc

Quando utilizzare Engine, Connection, Session in generale

  • Il motore è l'oggetto di livello più basso utilizzato da SQLAlchemy. Si mantiene un pool di connessioni disponibili per l'uso ogni volta che l'applicazione ha bisogno di parlare con il database. .execute()è un metodo pratico che prima chiama conn = engine.connect(close_with_result=True)e poi conn.execute(). Il parametro close_with_result indica che la connessione viene chiusa automaticamente. (Sto leggermente parafrasando il codice sorgente, ma essenzialmente vero). modifica: ecco il codice sorgente per engine.execute

    È possibile utilizzare il motore per eseguire SQL non elaborato.

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

    Questo è trattato nei documenti nell'uso di base .

  • La connessione è (come abbiamo visto sopra) la cosa che effettivamente fa il lavoro di esecuzione di una query SQL. Dovresti farlo ogni volta che desideri un maggiore controllo sugli attributi della connessione, quando viene chiuso, ecc. Ad esempio, un esempio molto importante di ciò è una Transazione , che ti consente di decidere quando eseguire il commit delle modifiche nel database. Nell'uso normale, le modifiche vengono eseguite automaticamente. Con l'uso delle transazioni, è possibile (ad esempio) eseguire diverse istruzioni SQL diverse e se qualcosa va storto con una di esse è possibile annullare tutte le modifiche contemporaneamente.

    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

    Ciò consentirebbe di annullare entrambe le modifiche in caso di errore, come se si fosse dimenticato di creare la tabella del registro dati.

    Quindi, se stai eseguendo codice SQL non elaborato e hai bisogno di controllo, usa le connessioni

  • Le sessioni vengono utilizzate per l'aspetto ORM (Object Relationship Management) di SQLAlchemy (in effetti puoi vederlo da come vengono importate:) from sqlalchemy.orm import sessionmaker. Usano connessioni e transazioni sotto il cofano per eseguire le loro istruzioni SQL generate automaticamente..execute()è una funzione di convenienza che passa a tutto ciò che la sessione è vincolata (di solito un motore, ma può essere una connessione).

    Se si utilizza la funzionalità ORM, utilizzare la sessione; se stai solo eseguendo query SQL dirette non associate a oggetti, probabilmente stai meglio usando le connessioni direttamente.


1
Le istruzioni di inserimento non dovrebbero essere racchiuse tra virgolette doppie ""?
mingchau,

2
@mingchau Sì, hai ragione, le mie virgolette singole avrebbero interferito l'una con l'altra, le doppie virgolette sono molto più facili da evitare. Aggiornato.
Neal

Data la sessione creata, come si collega la mia sessione con la mia connessione PostgreSQL?
Raju yourPepe,

@RajuyourPepe my_session.connection(). Documenti: docs.sqlalchemy.org/en/13/orm/… .
Neal,

Sul serio ? L'oggetto 'Sessione' non ha attributo 'connetti' ", è quello che ho trovato
Raju yourPepe

0

Ecco un esempio di esecuzione di DCL (Data Control Language) come GRANT

def grantAccess(db, tb, user):
  import sqlalchemy as SA
  import psycopg2

  url = "{d}+{driver}://{u}:{p}@{h}:{port}/{db}".\
            format(d="redshift",
            driver='psycopg2',
            u=username,
            p=password,
            h=host,
            port=port,
            db=db)
  engine = SA.create_engine(url)
  cnn = engine.connect()
  trans = cnn.begin()
  strSQL = "GRANT SELECT on table " + tb + " to " + user + " ;"
  try:
      cnn.execute(strSQL)
      trans.commit()
  except:
      trans.rollback()
      raise
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.