SQLAlchemy: silnik, połączenie i różnica sesji

Używam SQLAlchemy i są co najmniej trzy podmioty: engine, session i connection, które mają metodę execute, więc jeśli np. chcę wybrać wszystkie rekordy z table mogę to zrobić

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

I to

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

I nawet to

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

- wyniki będą takie same.

Jak rozumiem, jeśli ktoś używa engine.execute tworzy connection, otwiera session (Alchemia zajmuje się tym za Ciebie) i wykonuje zapytanie. Ale czy istnieje globalna różnica między tymi trzema sposobami wykonywania takich zadanie?

Author: Ricky McMaster, 2015-12-17

2 answers

Jednolinijkowy przegląd:

Zachowanie execute() jest takie samo we wszystkich przypadkach, ale są to 3 różne metody, w Engine, Connection, i Session klasy.

Czym dokładnie jest execute():

Aby zrozumieć zachowanie execute() musimy zajrzeć do klasy Executable. Executable jest klasą nadrzędną dla wszystkich typów obiektów typu "statement", w tym select (), delete (), update (), insert (), text () - w najprostszych słowach, Executable jest konstrukcją wyrażenia SQL obsługiwane w SQLAlchemy.

We wszystkich przypadkach metoda execute() pobiera tekst SQL lub skonstruowane wyrażenie SQL, tzn. dowolną z różnych konstrukcji wyrażeń SQL obsługiwanych w SQLAlchemy i zwraca wyniki zapytań (a ResultProxy - owija obiekt kursora DB-API, aby zapewnić łatwiejszy dostęp do kolumn wierszy.)


Do dalszego wyjaśnienia (tylko dla wyjaśnienia pojęciowego, a nie zalecanego podejścia):

Oprócz Engine.execute() (wykonanie bezpołączeniowe), Connection.execute(), i Session.execute(), możliwe jest również użycie execute() bezpośrednio na dowolnej konstrukcji Executable. Klasa Executable ma własną implementację execute() - zgodnie z oficjalną dokumentacją, jeden wiersz opisujący to, co robi execute() to " Skompiluj i wykonaj to Executable". W tym przypadku musimy jawnie powiązać Executable (konstrukt wyrażenia SQL) z obiektem Connection lub Engine (który domyślnie otrzymuje obiekt Connection), więc execute() będzie wiedział, gdzie wykonać SQL.

The poniższy przykład dobrze to pokazuje-podano tabelę jak poniżej:

from sqlalchemy import MetaData, Table, Column, Integer

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

Jawne wykonanie tj. Connection.execute() - przekazanie tekstu SQL lub skonstruowanego wyrażenia SQL do metody execute() Connection:

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

Explicit connectionless execution tj. Engine.execute() - przekazanie tekstu SQL lub skonstruowanego wyrażenia SQL bezpośrednio do metody execute() silnika:

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

Wykonanie niejawne tj. Executable.execute() - jest również bezpołączeniowe i wywołuje metodę execute() z Executable, to znaczy wywołuje metodę execute() bezpośrednio na konstrukcji wyrażenia SQL (instancja Executable).

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

Uwaga: podano niejawny przykład wykonania w celu wyjaśnienia-ten sposób wykonania jest wysoce odradzany - zgodnie z docs :

"implicit execution" jest bardzo starym wzorcem użycia, który w większości przypadków jest bardziej mylące niż pomocne, a jego użycie jest zniechęcające. Obie wzory wydają się zachęcać do nadużywanie celowych "skrótów" w projektowanie aplikacji, które później prowadzą do problemów.


Twoje pytania:

Jak rozumiem, jeśli ktoś używa silnika.wykonaj to tworzy połączenie, otwiera sesję (Alchemy dba o to za Ciebie) i wykonuje zapytanie.

Masz rację dla części " jeśli ktoś używa engine.execute tworzy connection", ale nie dla "otwiera session (Alchemia dba o to za Ciebie) i wykonuje zapytanie" - używając Engine.execute() i Connection.execute() jest (prawie) to samo, w formalnym Connection obiekt jest tworzony w sposób niejawny, a w późniejszym przypadku jawnie tworzymy jego instancję. To, co tak naprawdę dzieje się w tym przypadku, to:

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

Ale czy istnieje globalna różnica między tymi trzema sposobami wykonując takie zadanie?

W warstwie DB jest dokładnie to samo, wszystkie wykonują SQL(wyrażenia tekstowe lub różne konstrukcje wyrażeń SQL). Z punktu widzenia aplikacji istnieją dwa opcje:

  • Direct execution-Using Engine.execute() or Connection.execute()
  • Using sessions - efektywnie obsługuje transakcje jako pojedyncze jednostki pracy, z łatwością poprzez session.add(), session.rollback(), session.commit(), session.close(). Jest to sposób interakcji z DB w przypadku ORM tj. mapowanych tabel. Dostarcza identity_map do natychmiastowego uzyskania już dostępnych lub nowo utworzonych/dodanych obiektów podczas jednego żądania.

Session.execute() ostatecznie używa metody wykonywania instrukcji Connection.execute() w celu wykonaj polecenie SQL. Używanie obiektu Session jest zalecanym przez SQLAlchemy ORM sposobem interakcji aplikacji z bazą danych.

Fragment zdocs:

Ważne jest, aby pamiętać, że podczas korzystania z SQLAlchemy ORM, te obiekty nie są ogólnie dostępne; zamiast tego obiekt sesji jest używany jako interfejs do bazy danych. Jednak do zastosowań, które są zbudowane wokół bezpośredniego użycia tekstowych instrukcji SQL i / lub SQL wyrażenie konstrukcje bez udziału wyższego poziomu ORM usługi zarządzania, silnik i połączenie są król (i królowa?) - Czytaj dalej.

 58
Author: Nabeel Ahmed,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-01 02:06:33

Odpowiedź Nabeela obejmuje wiele szczegółów i jest pomocna, ale uważałem, że podążanie za nią jest mylące. Ponieważ jest to obecnie pierwszy wynik Google dla tego problemu, dodając moje zrozumienie tego dla przyszłych ludzi, którzy znajdą to pytanie:

Bieganie .execute ()

Jak zauważają zarówno op, jak i Nabell Ahmed, wykonując zwykły SELECT * FROM tablename, nie ma różnicy w podanym wyniku.

Różnice między tymi trzema obiektami stają się ważne w zależności od kontekst, w którym wyrażenie SELECT jest używane lub, częściej, gdy chcemy robić inne rzeczy, takie jak INSERT, DELETE, itd.

Kiedy używać silnika, połączenia, sesji ogólnie

  • Silnik jest obiektem najniższego poziomu używanym przez SQLAlchemy. To utrzymuje pulę połączeń dostępne do użytku, gdy aplikacja musi rozmawiać z bazą danych. {[6] } jest wygodną metodą, która najpierw wywołuje conn = engine.connect(close_with_result=True), a następnie conn.execute(). The close_with_result parametr oznacza, że połączenie zostanie zamknięte automatycznie. (Trochę parafrazuję kod źródłowy, ale zasadniczo prawda).

    Możesz użyć silnika do wykonania surowego SQL.

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

    Jest to omówione w dokumentach pod podstawowe użycie.

  • Connection jest (jak widzieliśmy powyżej) rzeczą, która faktycznie wykonuje pracę wykonania zapytania SQL. Powinieneś to zrobić, gdy chcesz mieć większą kontrolę nad atrybutami połączenia, gdy zostanie ono zamknięte, itd. Na przykład bardzo ważnym przykładem importu jest transakcja , która pozwala zdecydować, kiedy zatwierdzić zmiany w bazie danych. W normalnym użytkowaniu zmiany są automatycznie modyfikowane. Przy użyciu transakcji, można (na przykład) uruchomić kilka różnych poleceń SQL i jeśli coś pójdzie nie tak z jednym z nich można cofnąć wszystkie zmiany na raz.

    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
    

    To pozwoli Ci cofnąć obie zmiany, jeśli jedna się nie powiedzie, np. jeśli zapomnisz utworzyć tabelę datalog.

    Więc jeśli wykonujesz surowy kod SQL i potrzebujesz kontroli, użyj connections

  • Sesje {[27] } są używane do zarządzania relacjami z obiektami (ORM) w SQLAlchemy (w rzeczywistości można to zobaczyć po ich zaimportowaniu: from sqlalchemy.orm import sessionmaker). Używają Połączeń i transakcji pod maską do uruchamiania automatycznie generowanych poleceń SQL. {[6] } jest funkcją wygodną, która przechodzi do dowolnej sesji, z którą jest związana (Zwykle silnik, ale może być połączeniem).

    Jeśli używasz funkcjonalności ORM, użyj sesji; jeśli robisz tylko proste zapytania SQL nie związane z obiektami, prawdopodobnie lepiej będzie używać połączeń bezpośrednio.

 29
Author: Neal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:56