SQLAlchemy: perbedaan mesin, koneksi dan sesi

134

Saya menggunakan SQLAlchemy dan setidaknya ada tiga entitas: engine, sessiondan connection, yang memiliki executemetode, jadi jika saya misalnya ingin memilih semua catatan dari tablesaya bisa melakukan ini

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

dan ini

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

dan bahkan ini

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

- hasilnya akan sama.

Seperti yang saya pahami, jika seseorang menggunakannya engine.executemenciptakan connection, terbuka session(Alkimia mengurusnya untuk Anda) dan menjalankan kueri. Tetapi apakah ada perbedaan global antara ketiga cara ini dalam melakukan tugas seperti itu?

ololobus
sumber
Saya pikir jawaban Anda ada di sini: hackersandslackers.com/...
SeF

Jawaban:

123

Tinjauan satu garis:

Perilaku execute()adalah sama dalam semua kasus, tetapi mereka 3 metode yang berbeda, di Engine, Connection, dan Sessionkelas.

Apa sebenarnya itu execute():

Untuk memahami perilaku execute()kita perlu melihat ke dalam Executablekelas. Executableadalah superclass untuk semua "pernyataan" jenis objek, termasuk select (), delete (), update (), insert (), text () - dengan kata-kata sesederhana mungkin, dan Executablemerupakan konstruksi ekspresi SQL yang didukung oleh SQLAlchemy.

Dalam semua kasus, execute()metode ini menggunakan teks SQL atau ekspresi SQL yang dikonstruksi yaitu setiap variasi konstruksi ekspresi SQL yang didukung dalam SQLAlchemy dan mengembalikan hasil kueri (a ResultProxy- Membungkus DB-APIobjek kursor untuk memberikan akses yang lebih mudah ke kolom baris.)


Untuk memperjelasnya lebih lanjut (hanya untuk klarifikasi konseptual, bukan pendekatan yang disarankan) :

Selain Engine.execute()(eksekusi tanpa sambungan),, Connection.execute()dan Session.execute(), juga dimungkinkan untuk menggunakan execute()langsung pada Executablekonstruksi apa pun . The Executablekelas memiliki implementasi itu sendiri execute()- Sesuai dokumentasi resmi, satu baris deskripsi tentang apa yang execute()dilakukannya adalah " Kompilasi dan jalankan iniExecutable ". Dalam hal ini kita perlu secara eksplisit mengikat Executable(konstruksi ekspresi SQL) dengan Connectionobjek atau, Engineobjek (yang secara implisit mendapatkan Connectionobjek), sehingga execute()akan tahu di mana harus mengeksekusi SQL.

Contoh berikut menunjukkan dengan baik - Diberikan tabel seperti di bawah ini:

from sqlalchemy import MetaData, Table, Column, Integer

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

Eksekusi eksplisit yaitu Connection.execute()- meneruskan teks SQL atau membangun ekspresi SQL ke execute()metode Connection:

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

Eksekusi connectionless eksplisit yaitu Engine.execute()- melewati teks SQL atau membangun ekspresi SQL langsung ke execute()metode Engine:

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

Eksekusi implisit yaitu Executable.execute()- juga tanpa koneksi, dan memanggil execute()metode Executable, yaitu, memanggil execute()metode langsung pada SQLkonstruksi ekspresi (turunan dari Executable) itu sendiri.

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

Catatan: Menyebutkan contoh eksekusi implisit untuk tujuan klarifikasi - cara eksekusi ini sangat tidak disarankan - sesuai dokumen :

“Eksekusi implisit” adalah pola penggunaan yang sangat lama yang dalam kebanyakan kasus lebih membingungkan daripada membantu, dan penggunaannya tidak disarankan. Kedua pola tersebut tampaknya mendorong "jalan pintas" yang terlalu sering digunakan dalam desain aplikasi yang kemudian menimbulkan masalah.


Pertanyaan Anda:

Seperti yang saya mengerti jika seseorang menggunakan engine.execute itu membuat koneksi, buka sesi (Alchemy peduli untuk Anda) dan jalankan query.

Anda benar untuk bagian "jika seseorang menggunakannya engine.executemenciptakan connection" tetapi tidak untuk "terbuka session(Alkimia peduli untuk Anda) dan mengeksekusi permintaan" - Menggunakan Engine.execute()dan Connection.execute()(hampir) satu hal yang sama, secara formal, Connectionobjek dibuat secara implisit , dan dalam kasus selanjutnya kami secara eksplisit instantiate. Apa yang sebenarnya terjadi dalam kasus ini adalah:

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

Tetapi apakah ada perbedaan global antara ketiga cara ini dalam melakukan tugas seperti itu?

Pada lapisan DB itu hal yang persis sama, semuanya mengeksekusi SQL (ekspresi teks atau berbagai konstruksi ekspresi SQL). Dari sudut pandang aplikasi ada dua opsi:

  • Eksekusi langsung - Menggunakan Engine.execute()atauConnection.execute()
  • Menggunakan sessions- efisien menangani transaksi sebagai unit tunggal-of-kerja, dengan mudah melalui session.add(), session.rollback(), session.commit(), session.close(). Ini adalah cara untuk berinteraksi dengan DB jika ORM yaitu tabel yang dipetakan. Memberikan identity_map untuk secara instan mengakses objek yang baru dibuat / ditambahkan saat permintaan tunggal.

Session.execute()akhirnya menggunakan Connection.execute()metode eksekusi pernyataan untuk mengeksekusi pernyataan SQL. Menggunakan Sessionobjek adalah cara yang direkomendasikan oleh SQLAlchemy ORM untuk aplikasi berinteraksi dengan database.

Kutipan dari dokumen :

Penting untuk dicatat bahwa ketika menggunakan ORM SQLAlchemy, objek-objek ini umumnya tidak diakses; sebaliknya, objek Sesi digunakan sebagai antarmuka ke database. Namun, untuk aplikasi yang dibangun berdasarkan penggunaan langsung pernyataan SQL tekstual dan / atau konstruksi ekspresi SQL tanpa keterlibatan oleh layanan manajemen level ORM yang lebih tinggi, Engine dan Connection adalah raja (dan ratu?) - baca terus.

Nabeel Ahmed
sumber
Kata "tanpa koneksi" menyiratkan bahwa tidak ada koneksi yang dibuat, yang menurut jawaban Neal bukan itu masalahnya.
Atom
111

Jawaban Nabeel mencakup banyak detail dan sangat membantu, tetapi saya merasa bingung untuk mengikuti. Karena ini adalah hasil Google pertama untuk masalah ini, menambahkan pemahaman saya tentang hal itu untuk orang-orang masa depan yang menemukan pertanyaan ini:

Menjalankan .execute ()

Sebagaimana OP dan Nabell Ahmed sama-sama catat, ketika mengeksekusi sebuah dataran SELECT * FROM tablename, tidak ada perbedaan dalam hasil yang diberikan.

Perbedaan antara ketiga benda-benda ini menjadi penting tergantung pada konteks bahwa SELECTpernyataan digunakan dalam atau, lebih umum, ketika Anda ingin melakukan hal-hal lain seperti INSERT, DELETE, dll

Kapan menggunakan Engine, Connection, Session pada umumnya

  • Engine adalah objek level terendah yang digunakan oleh SQLAlchemy. Itu memelihara kumpulan koneksi yang tersedia untuk digunakan setiap kali aplikasi perlu berbicara dengan database..execute()adalah metode kenyamanan yang pertama kali memanggil conn = engine.connect(close_with_result=True)dan kemudian conn.execute(). Parameter close_with_result berarti koneksi ditutup secara otomatis. (Saya sedikit memparafrasekan kode sumber, tetapi pada dasarnya benar). sunting: Ini kode sumber untuk engine.execute

    Anda dapat menggunakan mesin untuk menjalankan SQL mentah.

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

    Ini tercakup dalam dokumen di bawah ini penggunaan dasar .

  • Koneksi (seperti yang kita lihat di atas) adalah hal yang benar-benar berfungsi mengeksekusi query SQL. Anda harus melakukan ini kapan pun Anda ingin kontrol yang lebih besar atas atribut koneksi, ketika itu ditutup, dll. Misalnya, contoh yang sangat penting dari ini adalah Transaksi , yang memungkinkan Anda memutuskan kapan akan melakukan perubahan Anda ke database. Dalam penggunaan normal, perubahan dilakukan secara otomatis. Dengan menggunakan transaksi, Anda dapat (misalnya) menjalankan beberapa pernyataan SQL yang berbeda dan jika ada yang salah dengan salah satunya, Anda dapat membatalkan semua perubahan sekaligus.

    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

    Ini akan memungkinkan Anda membatalkan kedua perubahan jika salah satu gagal, seperti jika Anda lupa membuat tabel datalog.

    Jadi jika Anda mengeksekusi kode SQL mentah dan perlu kontrol, gunakan koneksi

  • Sesi digunakan untuk aspek Object Relationship Management (ORM) dari SQLAlchemy (sebenarnya Anda dapat melihat ini dari cara mereka diimpor:) from sqlalchemy.orm import sessionmaker. Mereka menggunakan koneksi dan transaksi di bawah tenda untuk menjalankan pernyataan SQL yang dibuat secara otomatis. .execute()adalah fungsi kenyamanan yang melewati ke sesi apa pun terikat (biasanya mesin, tetapi dapat koneksi).

    Jika Anda menggunakan fungsionalitas ORM, gunakan sesi; jika Anda hanya melakukan query SQL langsung yang tidak terikat pada objek, Anda mungkin lebih baik menggunakan koneksi secara langsung.

Neal
sumber
1
Bukankah seharusnya memasukkan pernyataan terlampir dalam tanda kutip ganda ""?
mingchau
2
@mingchau Ya, Anda benar tanda kutip tunggal saya akan saling mengganggu, tanda kutip ganda jauh lebih mudah untuk menghindari masalah itu. Diperbarui.
Neal
Dengan sesi yang dibuat, bagaimana Sesi saya terhubung dengan koneksi PostgreSQL saya?
Raju yourPepe
@RajuyourPepe my_session.connection(). Documents: docs.sqlalchemy.org/en/13/orm/… .
Neal
Serius? Objek 'Sesi' tidak memiliki atribut 'terhubung' ", adalah apa yang saya temukan
Raju yourPepe
0

Berikut adalah contoh menjalankan DCL (Data Control Language) seperti 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
Jie
sumber