SQLAlchemy:エンジン、接続、セッションの違い


134

私はSQLAlchemyのを使用し、少なくとも3つのエンティティがあります:enginesessionconnection持って、executeこの方法は、私が例えばからすべてのレコードを選択したい場合はtable、私はこれを行うことができます

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

この

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

そしてこれさえ

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

-結果は同じになります。

私が理解しているように、誰かがengine.executeそれを使用するとconnection、が作成され、開かれsession(Alchemyが処理します)、クエリを実行します。しかし、そのようなタスクを実行するこれらの3つの方法の間に世界的な違いはありますか?


私はあなたの答えはここだと思う:hackersandslackers.com/...
SEF

回答:


123

1行の概要:

挙動は、execute()すべての場合に同じであるが、彼らは3種類の方法、であるEngineConnectionSessionクラス。

正確には何ですかexecute()

の動作を理解するにexecute()は、Executableクラスを調べる必要があります。Executableselect()、delete()、update()、insert()、text()を含むすべての「ステートメント」タイプのオブジェクトのスーパークラスです。最も簡単な言葉で言えば、ExecutableSQLAlchemyでサポートされているSQL式構成です。

すべての場合において、execute()メソッドはSQLテキストまたは構築されたSQL式、つまりSQLAlchemyでサポートされているさまざまなSQL式構成のいずれかを取り、クエリ結果を返します(ResultProxya- DB-APIカーソルオブジェクトをラップして、行列に簡単にアクセスできるようにします)。


それをさらに明確にするために(概念的な明確化のためにのみ、推奨されるアプローチではありません)

Engine.execute()(コネクションレス実行)、、Connection.execute()およびSession.execute()に加えてexecute()、任意のExecutable構成要素で直接を使用することもできます。Executableクラスは、それがの独自の実装のしているexecute()-公式ドキュメントを1として、どの程度1行の説明execute()ない「ですコンパイルし、これを実行しますExecutable」。この場合、Executable(SQL式構成)をConnectionオブジェクトまたはEngineオブジェクト(暗黙的にConnectionオブジェクトを取得する)に明示的にバインドする必要があるため、execute()はを実行する場所を認識しSQLます。

次の例はそれをうまく示しています-以下のようなテーブルが与えられます:

from sqlalchemy import MetaData, Table, Column, Integer

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

明示的な実行、つまりConnection.execute()SQLテキストまたは構築されたSQL式を次のexecute()メソッドに渡しますConnection

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

明示的なコネクションレス実行、つまりEngine.execute()SQLテキストまたは構築されたSQL式を直接execute()Engine のメソッドに渡します。

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

暗黙的な実行、つまりExecutable.execute()-もコネクションレスであり、のexecute()メソッドを呼び出します。つまり、式構成体(のインスタンス)自体で直接メソッドをExecutable呼び出します。execute()SQLExecutable

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

注:明確化の目的で暗黙の実行例を示しました-この実行方法は強く推奨されていません- ドキュメントに従って:

「暗黙的実行」は非常に古い使用パターンであり、ほとんどの場合、役立つよりも混乱を招くため、その使用はお勧めしません。どちらのパターンも、後で問題につながるアプリケーション設計での便利な「ショートカット」の使いすぎを助長しているようです。


あなたの質問:

私が理解しているように、engine.executeを使用すると、接続が作成され、セッションが開かれ(Alchemyが処理します)、クエリを実行します。

あなたの部分のためにしている権利を「誰かの使用があればengine.execute、それは作成connectionではなく、」開くために「session(錬金術あなたのためにそれを気)と実行はクエリ」 -使用するEngine.execute()Connection.execute()1つの同じこと(ほとんど)で、正式には、Connectionオブジェクトが暗黙的に作成されます、そして後のケースではそれを明示的にインスタンス化します。この場合に実際に何が起こるかは次のとおりです。

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

しかし、そのようなタスクを実行するこれらの3つの方法には、世界的な違いがありますか?

DBレイヤーでもまったく同じです。それらはすべてSQL(テキスト式またはさまざまなSQL式構成)を実行しています。アプリケーションの観点から、2つのオプションがあります。

  • 直接実行- Engine.execute()またはの使用Connection.execute()
  • 使用するsessions-効率介して容易に、単一の作業単位としてトランザクションを処理しますsession.add()session.rollback()session.commit()session.close()。これは、ORM、つまりマッピングされたテーブルの場合にDBと対話する方法です。単一のリクエスト中に、すでにアクセスされたオブジェクトまたは新しく作成/追加されたオブジェクトを即座に取得するためのidentity_mapを提供します。

Session.execute()最終的にはConnection.execute()、SQLステートメントを実行するためにステートメント実行メソッドを使用します。Sessionオブジェクトを使用することは、アプリケーションがデータベースと対話するためのSQLAlchemy ORMの推奨される方法です。

ドキュメントからの抜粋:

SQLAlchemy ORMを使用する場合、これらのオブジェクトは通常アクセスされないことに注意することが重要です。代わりに、Sessionオブジェクトがデータベースへのインターフェースとして使用されます。ただし、ORMの上位レベルの管理サービスの関与なしに、テキストSQLステートメントやSQL式構造体を直接使用するように構築されたアプリケーションの場合、エンジンと接続は王様(そして女王様?)です。


「コネクションレス」という言葉は、コネクションが作成されていないことを意味しますが、ニールの回答によるとそうではありません。
Atom

110

Nabeelの答えは多くの詳細をカバーしていて役に立ちますが、私はそれを理解するのが難しいと思いました。これは現在、この問題に対する最初のGoogleの結果なので、この質問を見つけた将来の人々に私の理解を追加します。

.execute()の実行

OPとNabell Ahmedの両方が指摘しているように、plainを実行しても、SELECT * FROM tablename提供される結果に違いはありません。

これらの3つのオブジェクト間の違いがあることコンテキストに応じて重要になってないSELECT文がまたは、より一般的に、あなたがしたいときのような他のものに使用されているINSERTDELETEなど

エンジン、接続、セッションを一般的に使用する場合

  • Engineは、SQLAlchemyが使用する最低レベルのオブジェクトです。これは、接続のプールを維持アプリケーションがデータベースに話をする必要があるときに使用できます。.execute()は最初に呼び出しconn = engine.connect(close_with_result=True)、次にを呼び出す便利なメソッドですconn.execute()。close_with_resultパラメータは、接続が自動的に閉じられることを意味します。(私はソースコードを少し言い換えていますが、本質的には真実です)。編集:engine.executeのソースコードは次のとおりです

    エンジンを使用して生の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()

    これは、基本的な使用法のドキュメントで説明されています

  • 接続は(上記で見たように)SQLクエリを実行する作業を実際に行うものです。接続の属性をより詳細に制御したいとき、接続が閉じられたときなどに、これを行う必要があります。たとえば、これの非常に重要なインポートの例はトランザクションです。、これを実行する必要があります。であり、データベースへの変更をいつコミットするかを決定できます。通常の使用では、変更は自動コミットされます。トランザクションを使用すると、(たとえば)いくつかの異なるSQLステートメントを実行でき、そのうちの1つに問題が発生した場合は、すべての変更を一度に取り消すことができます。

    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

    これにより、データログテーブルの作成を忘れた場合など、一方が失敗した場合に両方の変更を取り消すことができます。

    したがって、生のSQLコードを実行していて制御が必要な場合は、接続を使用してください。

  • セッションは、SQLAlchemyのオブジェクト関係管理(ORM)の側面で使用されます(実際には、セッションのインポート方法からこれを確認できます:)from sqlalchemy.orm import sessionmaker。内部で接続とトランザクションを使用して、自動生成されたSQLステートメントを実行します。.execute()セッションがバインドされているものすべてにパススルーする便利な関数です(通常はエンジンですが、接続の場合もあります)。

    ORM機能を使用している場合は、セッションを使用します。オブジェクトにバインドされていない単純なSQLクエリのみを実行する場合は、接続を直接使用する方がよいでしょう。


1
挿入ステートメントを二重引用符で囲まないでください""
mingchau

2
@mingchauええ、そうです、私の単一引用符はお互いに干渉しているでしょうね。二重引用符はその問題を回避する方がはるかに簡単です。更新しました。
ニール

作成されたセッションが与えられた場合、私のセッションはどのようにPostgreSQL接続にリンクされますか?
Raju yourPepe

@RajuyourPepe my_session.connection()。ドキュメント:docs.sqlalchemy.org/en/13/orm/…
ニール

マジ?'Session'オブジェクトには属性 'connect'がありません。これは私が見つけたものです
Raju yourPepe

0

GRANTなどのDCL(データ制御言語)を実行する例を以下に示します。

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.