1. ホーム
  2. python

[解決済み] SQLAlchemy: セッションの作成と再利用

2022-07-12 13:57:12

質問

ちょっとした質問です。SQLAlchemy について話しています。 呼び出し sessionmaker() を一度呼び出すが、その結果生じる Session() クラスを呼び出します。私の場合、これは最初の session.add(x) などと書くと、まず

from project import Session
session = Session()

いままでやっていたのは、呼び出しが session = Session() をモデル内で 一度 を作成し、アプリケーションのどこにいても常に同じセッションをインポートします。これはWebアプリケーションなので、このようになります。 通常 という意味です。

しかし、どこに違いがあるのでしょうか?自分の関数が終了するまでデータベースのためにセッションを使用し、次にDBと話をしたいときに新しいセッションを作成することに対して、常に1つのセッションを使用することの不利な点は何でしょうか?

複数のスレッドを使用する場合、それぞれが独自のセッションを取得する必要があることは理解しました。しかし scoped_session() を使うことで、その問題が存在しないことをすでに確認していますよね?

私の仮定に間違いがあれば、明らかにしてください。

どのように解決するのですか?

sessionmaker() はファクトリで、これは新しい Session オブジェクトを作成するための設定オプションを一か所にまとめることを推奨しています。 これはオプションです。 Session(bind=engine, expire_on_commit=False) をいつでも呼び出すことができます。 Session が必要な場合、その冗長性と冗長性を除いては、私は、それぞれが新しい、より混乱させる方法でこの冗長性の問題にアプローチする小規模な "ヘルパー"の増殖を止めたいと思いました。

そこで sessionmaker() を作成するためのツールに過ぎません。 Session オブジェクトを作成するためのツールに過ぎません。

次の部分です。 問題は、新しい Session() を作るのと、ずっと1つだけ使うのとでは何が違うのかということです。 答え、あまりありません。 Session は、あなたがそこに入れたすべてのオブジェクトのためのコンテナであり、そしてそれはまた、開いているトランザクションを追跡します。 を呼び出した瞬間に rollback() または commit() であれば、トランザクションは終了し Session は再びSQLを発行するように要求されるまで、データベースへの接続を持ちません。 マップされたオブジェクトへのリンクは弱い参照で、オブジェクトが保留中の変更から解放されていれば、その点でも Session は、アプリケーションがマップされたオブジェクトへの参照をすべて失うと、それ自体が空になって、まったく新しい状態に戻ってしまいます。 これをデフォルトの "expire_on_commit" の設定のままにしておくと、コミット後にすべてのオブジェクトが失効してしまいます。 もし、その Session が 5 分から 20 分間放置され、次に使用するときにデータベース内のあらゆるものが変更されていた場合、それらのオブジェクトが 20 分間メモリ内に置かれていたとしても、次にアクセスするときにはすべての新しい状態がロードされます。

ウェブアプリケーションでは、通常、なぜ新しい Session を作ったらどうでしょうか? この方法は、新しいリクエストがクリーンな状態で開始されることを保証します。 前のリクエストのオブジェクトがまだガベージコレクションされていない場合、そしてもしかしたら "expire_on_commit" をオフにした場合、前のリクエストからいくつかの状態がまだぶら下がっていて、その状態はかなり古いものである可能性さえあります。 もしあなたが注意深く expire_on_commit をオンにしたままにしておき、間違いなく commit() または rollback() で始まる場合は問題ないのですが、全く新しい Session で始めるなら、クリーンな状態で始めていることに疑問の余地はないでしょう。 そこで、各リクエストを新しい Session を使うのは、本当に一番簡単な方法です。 expire_on_commit を呼び出す操作のために多くの余分な SQL が発生する可能性があるため、このフラグはほとんどオプションです。 commit() を呼び出すような操作では、余分な SQL が発生する可能性があるからです。 これが質問の答えになるかどうかは分かりませんが。

次のラウンドは、スレッドについて言及されているものです。 アプリがマルチスレッド化されている場合は、必ず Session 使用中がローカルで...何か。 scoped_session() はデフォルトで現在のスレッドにローカルになります。 Web アプリでは、リクエストに対してローカルであることは、実際にはもっと良いことです。 Flask-SQLAlchemy は実際にカスタム "スコープ関数" を scoped_session() に送るので、リクエストスコープのセッションを得ることができます。 平均的なPyramidアプリケーションは、Sessionを"request"レジストリに貼り付けます。 これらのようなスキームを使用する場合、"create new Session on request start"のアイデアは、物事を整理する最も簡単な方法のように見え続けています。