Connection Pooling

接続プールは、効率的な再利用のために長時間実行される接続をメモリー内に保持したり、アプリケーションが同時に使用する可能性のある接続の総数を管理したりするために使用される標準的な手法です。

特にサーバー・サイドのWebアプリケーションの場合、接続プールは、メモリー内のアクティブなデータベース接続のプールを維持するための標準的な方法であり、この”プール”は要求間で再利用されます。

SQLAlchemyには、 Engine と統合される接続プールの実装がいくつか含まれています。また、通常のDBAPIアプローチにプーリングを追加したいアプリケーションで直接使用することもできます。

Connection Pool Configuration

ほとんどの場合、 create_engine() 関数が返す Engine には QueuePool が統合されていて、適切なプーリングのデフォルトで事前に設定されています。プーリングを有効にする方法を学ぶためだけにこのセクションを読んでいるのであれば、おめでとうございます!もう終わりました。

最も一般的な QueuePool チューニングパラメータは、キーワード引数として create_engine() に直接渡すことができます:pool_sizemax_overflowpool_recyclepool_timeout。例:

engine = create_engine(
    "postgresql+psycopg2://me@localhost/mydb", pool_size=20, max_overflow=0
)

すべてのSQLAlchemyプール実装に共通しているのは、どの実装も接続を”事前作成”しないということです。すべての実装は、接続を作成する前に最初に使用されるまで待機します。その時点で、追加の接続に対する追加の同時チェックアウト要求が行われなければ、追加の接続は作成されません。これが、アプリケーションが実際に5つの接続をキューに入れる必要があるかどうかに関係なく、 create_engine() がデフォルトでサイズ5の QueuePool を使用することが完全に問題ない理由です。アプリケーションが実際に5つの接続を同時に使用した場合にのみ、プールはそのサイズに成長します。その場合、小さなプールの使用は完全に適切なデフォルト動作です。

Note

QueuePool クラスは asyncioと互換性がありませんcreate_async_engine を使用して AsyncEngine のインスタンスを作成する場合、asyncio互換のキュー実装を利用する AsyncAdaptedQueuePool クラスが代わりに使用されます。

Switching Pool Implementations

create_engine() で別の種類のプールを使用する一般的な方法は、引数 poolclass を使用することです。この引数は sqlalchemy.pool モジュールからインポートされたクラスを受け入れ、プールの構築の詳細を処理します。ここでの一般的な使用例は、接続プーリングを無効にする場合で、これは NullPool 実装を使用して実現できます:

from sqlalchemy.pool import NullPool

engine = create_engine(
    "postgresql+psycopg2://scott:tiger@localhost/test", poolclass=NullPool
)

Using a Custom Connection Function

さまざまな接続カスタマイズルーチンの詳細については Custom DBAPI connect() arguments / on-connect routines を参照してください。

Constructing a Pool

Pool を単独で使用するには、必要な引数は creator 関数だけで、最初に渡され、その後に追加のオプションが続きます:

import sqlalchemy.pool as pool
import psycopg2

def getconn():
    c = psycopg2.connect(user="ed", host="127.0.0.1", dbname="test")
    return c

mypool = pool.QueuePool(getconn, max_overflow=10, pool_size=5)

次に、 Pool.connect() 関数を使用して、プールからDBAPI接続を取得できます。このメソッドの戻り値は、透過プロキシに含まれるDBAPI接続です:

# get a connection
conn = mypool.connect()

# use it
cursor_obj = conn.cursor()
cursor_obj.execute("select foo")

透過プロキシーの目的は、DBAPI接続が閉じられる代わりにプールに返されるように、 close() 呼び出しをインターセプトすることです。:

# "close" the connection.  Returns
# it to the pool.
conn.close()

またプロキシーは、ガーベッジ・コレクションが行われたときに、含まれているDBAPI接続をプールに戻しますが、これがすぐに行われるかどうかはPythonでは確定的ではありません(cPythonでは一般的ですが)。ただし、この使用方法は推奨されておらず、特にasyncio DBAPIドライバではサポートされていません。

Reset On Return

このプールには、接続がプールに戻されたときにDBAPI接続の rollback() メソッドを呼び出す”reset on return”動作が含まれています。これは、コミットされていないデータだけでなく、テーブル・ロックやロー・ロックも含めて、既存のトランザクション状態が接続から削除されるようにするためです。ほとんどのDBAPIでは、 rollback() の呼び出しは安価であり、DBAPIがすでにトランザクションを完了している場合、このメソッドは何の操作も行わないはずです。

Disabling Reset on Return for non-transactional connections

autocommit 用に設定された接続を使用している場合や、MySQLのMyISAMエンジンのようなACID機能を持たないデータベースを使用している場合など、この rollback() が役に立たない非常に特殊なケースでは、reset-on-returnの動作を無効にすることができます。これは通常、パフォーマンス上の理由から行われます。これは、 PoolPool.reset_on_return パラメータを使用することで影響を受ける可能性があります。このパラメータは create_engine() から create_engine.pool_reset_on_return としても利用でき、値``None``を渡します。これは以下の例で、 create_engine.isolation_level パラメータ設定の``AUTOCOMMIT``と組み合わせて説明されています:

non_acid_engine = create_engine(
    "mysql://scott:tiger@host/db",
    pool_reset_on_return=None,
    isolation_level="AUTOCOMMIT",
)

上記のエンジンは、接続がプールに戻されても実際にはROLLBACKを実行しません。AUTOCOMMITが有効になっているので、ドライバはBEGIN操作も実行しません。

Custom Reset-on-Return Schemes

単一の rollback() で構成される reset on return は、いくつかのユースケースでは十分ではないかもしれません。特に、テンポラリ・テーブルを使用するアプリケーションでは、これらのテーブルが接続のチェックイン時に自動的に削除されることを望む場合があります。一部の(ただし、すべてではありません)バックエンドには、データベース接続の範囲内でそのようなテーブルを リセット できる機能が含まれています。これは、接続プールのリセットに望ましい動作です。準備された文のハンドルやサーバ側の文キャッシュなどの他のサーバリソースは、チェックインプロセスを超えて持続する場合があります。これは、詳細に応じて望ましい場合と望ましくない場合があります。ここでも、一部の(ただし、すべてではありません)バックエンドは、この状態をリセットする手段を提供する場合があります。このようなリセット方式を持つことが知られている2つのSQLAlchemyに含まれる方言には、Microsoft SQL Serverが含まれます。Microsoft SQL Serverでは、文書化されていないが広く知られている sp_reset_connection というストアドプロシージャがよく使用されます。PostgreSQLでは、 DISCARD RESET DEALLOCATE UNLISTEN などの一連のコマンドが十分に文書化されています。

次の例は、 PoolEvents.reset() イベントフックを使って、reset on returnをMicrosoft SQL Serverの sp_reset_connection ストアドプロシージャに置き換える方法を示しています。 create_engine.pool_reset_on_return パラメータは None に設定されているので、カスタムスキームはデフォルトの動作を完全に置き換えることができます。カスタムフックの実装は、DBAPI自身のコミット/ロールバックの追跡がトランザクションの状態と一貫性を保つことが通常重要であるため、いかなる場合でも .rollback() を呼び出します。:

from sqlalchemy import create_engine
from sqlalchemy import event

mssql_engine = create_engine(
    "mssql+pyodbc://scott:tiger^5HHH@mssql2017:1433/test?driver=ODBC+Driver+17+for+SQL+Server",
    # disable default reset-on-return scheme
    pool_reset_on_return=None,
)

@event.listens_for(mssql_engine, "reset")
def _reset_mssql(dbapi_connection, connection_record, reset_state):
    if not reset_state.terminate_only:
        dbapi_connection.execute("{call sys.sp_reset_connection}")

    # so that the DBAPI itself knows that the connection has been
    # reset
    dbapi_connection.rollback()

Changed in version 2.0.0b3: PoolEvents.reset() イベントに状態引数を追加し、すべての”reset”発生に対してイベントが呼び出されるようにしました。これにより、カスタム”reset”ハンドラの場所として適切になります。 PoolEvents.checkin() ハンドラを使用する以前のスキームも引き続き使用できます。

Logging reset-on-return events

Re set on returnを含むプールイベントのロギングは、 logging.DEBUG ログレベルを sqlalchemy.pool ロガーと一緒に設定するか、 create_engine() を使用するときに create_engine.echo_pool を````”debug”`` に設定することで設定できます:

>>> from sqlalchemy import create_engine
>>> engine = create_engine("postgresql://scott:tiger@localhost/test", echo_pool="debug")

上記のプールは、終了時のリセットを含む詳細なログを表示します:

>>> c1 = engine.connect()
DEBUG sqlalchemy.pool.impl.QueuePool Created new connection <connection object ...>
DEBUG sqlalchemy.pool.impl.QueuePool Connection <connection object ...> checked out from pool
>>> c1.close()
DEBUG sqlalchemy.pool.impl.QueuePool Connection <connection object ...> being returned to pool
DEBUG sqlalchemy.pool.impl.QueuePool Connection <connection object ...> rollback-on-return

Pool Events

接続プールは、最初の接続時、新しい接続時、および接続のチェックアウトとチェックイン時にフックを実行できるようにするイベントインタフェースをサポートしています。詳細は PoolEvents を参照してください。

Dealing with Disconnects

接続プールには、個々の接続およびその接続セット全体をリフレッシュする機能があり、以前にプールされた接続を”無効”として設定します。一般的な使用例は、データベース・サーバーが再起動され、以前に確立されたすべての接続が機能しなくなったときに、接続プールを正常にリカバリできるようにすることです。これには2つのアプローチがあります。

Disconnect Handling - Pessimistic

悲観的アプローチでは、各接続プール・チェックアウトの開始時にSQL接続に対してテスト・ステートメントを発行して、データベース接続がまだ有効であることをテストします。この実装は方言固有であり、DB API固有のpingメソッドを使用するか、”SELECT 1”のような単純なSQL文を使用して接続が有効かどうかをテストします。

この方法では、接続のチェックアウト・プロセスにわずかなオーバーヘッドが追加されますが、プールされた古い接続によるデータベース・エラーを完全に排除するための最も簡単で信頼性の高い方法です。呼び出し側アプリケーションは、プールからチェックアウトされた古い接続から回復できるように操作を編成する必要はありません。

チェックアウト時の接続の悲観的なテストは、 create_engine.pool_pre_ping 引数を介して create_engine() から利用可能な Pool.pre_ping 引数を使用することで実現できます:

engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)

“事前ping”機能は、adBAPI固有の”ping”メソッドを呼び出すか、使用できない場合は”SELECT 1”と同等のSQLを出力してエラーをキャッチし、そのエラーを”切断”状態として検出することによって、方言ごとに動作します。ping/エラーチェックによって接続が使用できないと判断された場合、その接続はすぐにリサイクルされ、現在の時刻よりも古い他のすべてのプールされた接続は無効になるため、次にチェックアウトされるときにも使用前にリサイクルされます。

“pre ping”の実行時にデータベースがまだ使用できない場合、初期接続は失敗し、接続失敗のエラーが正常に伝達されます。データベースが接続に使用可能であるが、”ping”に応答できないというまれな状況では、”pre_ping”は、最後に受信したデータベース・エラーを伝播して、終了するまで最大3回試行します。

事前pingアプローチでは、 トランザクションやその他のSQL操作の途中で切断された接続に対応できないことに注意してください 。トランザクションの進行中にデータベースが使用できなくなると、トランザクションが失われ、データベースエラーが発生します。 Connection オブジェクトが”切断”状態を検出し、接続をリサイクルし、この状態が発生したときに残りの接続プールを無効にしますが、例外が発生した個々の操作は失われ、操作を放棄するか、トランザクション全体を再試行するかはアプリケーション次第です。 Setting Transaction Isolation Levels including DBAPI Autocommit で説明されているように、エンジンがDB APIレベルのオートコミット接続を使用して設定されている場合、接続はイベントを使用して操作の途中で透過的に再接続される 可能性があります 。例については How Do I “Retry” a Statement Execution Automatically? を参照してください。

“SELECT 1”を使用し、切断を検出するためにエラーをキャッチするダイアレクトでは、 DialectEvents.handle_error() フックを使用して、新しいバックエンド固有のエラーメッセージに対して切断テストを拡張することができます。

Custom / Legacy Pessimistic Ping

create_engine.pool_pre_ping が追加される前は、歴史的に”pre-ping”アプローチは ConnectionEvents.engine_connect() エンジンイベントを使用して手動で実行されていました。アプリケーションがすでにこのようなレシピを使用している場合、または特殊な動作が必要な場合の参考のために、最も一般的なレシピを以下に示します。:

from sqlalchemy import exc
from sqlalchemy import event
from sqlalchemy import select

some_engine = create_engine(...)

@event.listens_for(some_engine, "engine_connect")
def ping_connection(connection, branch):
    if branch:
        # this parameter is always False as of SQLAlchemy 2.0,
        # but is still accepted by the event hook.  In 1.x versions
        # of SQLAlchemy, "branched" connections should be skipped.
        return

    try:
        # run a SELECT 1.   use a core select() so that
        # the SELECT of a scalar value without a table is
        # appropriately formatted for the backend
        connection.scalar(select(1))
    except exc.DBAPIError as err:
        # catch SQLAlchemy's DBAPIError, which is a wrapper
        # for the DBAPI's exception.  It includes a .connection_invalidated
        # attribute which specifies if this connection is a "disconnect"
        # condition, which is based on inspection of the original exception
        # by the dialect in use.
        if err.connection_invalidated:
            # run the same SELECT again - the connection will re-validate
            # itself and establish a new connection.  The disconnect detection
            # here also causes the whole connection pool to be invalidated
            # so that all stale connections are discarded.
            connection.scalar(select(1))
        else:
            raise

上記のレシピには、”切断”状態を示すことがわかっているDBAPI例外を検出するためにSQLAlchemyの機能を利用しているという利点があります。また、この条件が発生したときに Engine オブジェクトが現在の接続プールを正しく無効にし、現在の Connection が新しいDBAPI接続を再有効化できるという利点もあります。

Disconnect Handling - Optimistic

悲観的処理が使用されていない場合や、トランザクション内で接続が使用されている途中でデータベースがシャットダウンまたは再起動された場合、古い/閉じられた接続を処理するもう1つの方法は、切断が発生したときにSQLAlchemyに切断を処理させることです。切断が発生すると、プール内のすべての接続が無効になります。つまり、切断は古いものと見なされ、次のチェックアウト時に更新されます。この動作は、 PoolEngine と組み合わせて使用されることを前提としています。 Engine には、切断イベントを検出してプールを自動的に更新するロジックがあります。

Connection がDBAPI接続を使用しようとし、”切断”イベントに対応する例外が発生した場合、接続は無効になります。その後、 ConnectionPool.recreate() メソッドを呼び出し、現在チェックアウトされていないすべての接続を実質的に無効にして、次のチェックアウト時に新しい接続に置き換えられるようにします。この流れを以下のコード例で示します。:

from sqlalchemy import create_engine, exc

e = create_engine(...)
c = e.connect()

try:
    # suppose the database has been restarted.
    c.execute(text("SELECT * FROM table"))
    c.close()
except exc.DBAPIError as e:
    # an exception is raised, Connection is invalidated.
    if e.connection_invalidated:
        print("Connection was invalidated!")

# after the invalidate event, a new connection
# starts with a new Pool
c = e.connect()
c.execute(text("SELECT * FROM table"))

上記の例は、切断イベントが検出された後もプールを更新するために特別な介入が必要ないことを示しています。ただし、データベース使用不可イベントが発生している間に使用されている接続ごとに、1つのデータベース例外が発生します。ORMセッションを使用する一般的なWebアプリケーションでは、上記の条件は、500エラーで失敗した単一の要求に対応し、Webアプリケーションはそれを超えて正常に継続します。したがって、頻繁なデータベースの再起動が予想されないという点で、このアプローチは”楽観的”です。

Setting Pool Recycle

“楽観的”アプローチを補強する追加の設定は、プールのリサイクルパラメータを設定することです。このパラメータは、特定の経過時間を経過した特定の接続がプールで使用されないようにします。また、特定の期間が経過した古い接続を自動的に閉じるMySQLなどのデータベースバックエンドに適しています。:

from sqlalchemy import create_engine

e = create_engine("mysql+mysqldb://scott:tiger@localhost/test", pool_recycle=3600)

上記では、1時間以上開いていたDBAPI接続は、次回のチェックアウト時に無効にされ、置き換えられます。無効化はチェックアウト中に**のみ**発生し、チェックアウト状態に保持されている接続では発生しないことに注意してください。 pool_recyclePool 自体の関数で、 Engine が使用されているかどうかとは無関係です。

More on Invalidation

Pool は、接続の明示的な無効化と、接続を使用不能にすると判断された条件に応じた自動的な無効化の両方を可能にする”接続無効化”サービスを提供します。

“無効化”とは、特定のDBAPI接続がプールから削除され、破棄されることを意味します。接続自体が閉じられない可能性があることが明確でない場合は、この接続で .close() メソッドが呼び出されます。ただし、このメソッドが失敗した場合は、例外がログに記録されますが、操作は続行されます。

Engine を使用する場合、 Connection.invalidate() メソッドが明示的な無効化の通常のエントリポイントになります。DBAPI接続が無効化されるその他の条件には、次のものがあります。

  • OperationalError のようなDBAPI例外は、 connection.execute() のようなメソッドが呼ばれた時に発生し、いわゆる”切断”状態を示すものとして検出されます。PythonのDBAPIは例外の性質を決定する標準システムを提供していないので、すべてのSQLAlchemyダイアレクトには is_disconnect() と呼ばれるシステムが含まれています。このシステムは、例外オブジェクトの内容を、文字列メッセージとそれに含まれる潜在的なエラーコードを含めて調べ、この例外が接続がもはや使用できないことを示しているかどうかを判断します。この場合、 _ConnectionFairy.invalidate() メソッドが呼び出され、DBAPI接続は破棄されます。

  • 接続がプールに戻され、プールの”reset on return”動作によって指示されているように、 connection.rollback() または connection.commit() メソッドを呼び出すと、例外がスローされます。接続に対して最後に close() を呼び出そうとする試みが行われ、その後破棄されます。

  • PoolEvents.checkout() を実装しているリスナが DisconnectError 例外を発生させた場合、これは接続が使用できなくなり、新しい接続を試みる必要があることを示します。

発生するすべての無効化は、 PoolEvents.invalidate() イベントを呼び出します。

Supporting new database error codes for disconnect scenarios

SQLAlchemyの各ダイアレクトには、DBAPI例外が発生するたびに呼び出される is_disconnect() というルーチンが含まれています。DBAPI例外オブジェクトがこのメソッドに渡され、ダイアレクト固有のヒューリスティックが、受け取ったエラーコードがデータベース接続が”切断された”ことを示しているのか、それとも再利用すべきであることを示す使用不能な状態にあることを示しているのかを判断します。ここで適用されるヒューリスティックは、 DialectEvents.handle_error() イベントフックを使用してカスタマイズできます。これは通常、所有する Engine オブジェクトを介して確立されます。このフックを使用すると、発生したすべてのエラーは ExceptionContext と呼ばれるコンテキストオブジェクトを介して配信されます。カスタムイベントフックは、特定のエラーを”切断”状態と見なすかどうか、およびこの切断によって接続プール全体が切断されるかどうかを制御できます。

例えば、Oracleのエラーコード DPY-1001DPY-4011 を切断コードとして扱うサポートを追加するには、生成後にエンジンにイベントハンドラを適用します:

import re

from sqlalchemy import create_engine

engine = create_engine("oracle://scott:tiger@dnsname")

@event.listens_for(engine, "handle_error")
def handle_exception(context: ExceptionContext) -> None:
    if not context.is_disconnect and re.match(
        r"^(?:DPI-1001|DPI-4011)", str(context.original_exception)
    ):
        context.is_disconnect = True

    return None

上記のエラー処理関数は、発生したすべてのOracleエラーに対して呼び出されます。これには、切断エラー処理に依存するバックエンドに対して pool pre ping 機能を使用したときに検出されたエラーも含まれます(2.0の新機能)。

Using FIFO vs. LIFO

QueuePool クラスには QueuePool.use_lifo というフラグがあります。これは create_engine() から create_engine.pool_use_lifo フラグを介してアクセスすることもできます。このフラグを に設定すると、プールの”キュー”の動作が”スタック”の動作になります。例えば、プールに返される最後の接続は、次の要求で使用される最初の接続です。プール内の各接続を連続して使用するラウンドロビン効果を生み出す先入れ先出しのプールの長年の動作とは対照的に、lifoモードでは、過剰な接続をプール内でアイドル状態のままにし、サーバ側のタイムアウトスキームでこれらの接続を閉じることができます。FIFOとLIFOの違いは、基本的に、プールがアイドル状態の間でも接続の完全なセットを準備しておくことが望ましいかどうかということです。

engine = create_engine(“postgreql://”, pool_use_lifo=True, pool_pre_ping=True)

上記では create_engine.pool_pre_ping フラグも使用していますので、サーバ側からクローズされたコネクションはコネクションプールによって自動的に処理され、新しいコネクションに置き換えられます。

このフラグは QueuePool の使用にのみ適用されることに注意してください。

New in version 1.3.

Using Connection Pools with Multiprocessing or os.fork()

接続プールを使用する場合、さらには create_engine() によって作成された Engine を使用する場合には、プールされた接続が 分岐したプロセスに共有されない ことが重要です。TCP接続はファイル記述子として表現され、通常はプロセスの境界を越えて動作します。つまり、完全に独立した2つ以上のPythonインタプリタ状態に代わって、ファイル記述子への同時アクセスが発生します。

ドライバやOSの仕様にもよりますが、ここで発生する問題は、動作しない接続から、複数のプロセスによって同時に使用されるソケット接続まで多岐にわたり、メッセージの破損につながります(後者のケースが一般的です)。

SQLAlchemy Engine オブジェクトは、既存のデータベース接続の接続プールを参照します。そのため、このオブジェクトが子プロセスにレプリケートされるときの目的は、データベース接続が引き継がれないようにすることです。これには4つの一般的なアプローチがあります。

  1. NullPool を使ってプーリングを無効にします。これは、 Engine がどのコネクションも2回以上使わないようにする、最も単純なワンショットシステムです:

    from sqlalchemy.pool import NullPool
    
    engine = create_engine("mysql+mysqldb://user:pass@host/dbname", poolclass=NullPool)
  1. 任意の EngineEngine.dispose() を呼び出し、子プロセスの初期化フェーズで Engine.dispose.close パラメータに`False`の値を渡します。これは、新しいプロセスが親プロセスの接続に接触せず、代わりに新しい接続から開始するようにするためです。 これは推奨されるアプローチです

    from multiprocessing import Pool
    
    engine = create_engine("mysql+mysqldb://user:pass@host/dbname")
    
    def run_in_process(some_data_record):
        with engine.connect() as conn:
            conn.execute(text("..."))
    
    def initializer():
        """ensure the parent proc's database connections are not touched
        in the new connection pool"""
        engine.dispose(close=False)
    
    with Pool(10, initializer=initializer) as p:
        p.map(run_in_process, data)

    New in version 1.4.33: Engine.dispose.close パラメータが追加されました。これにより、親プロセスが使用する接続に干渉することなく、子プロセス内の接続プールを置き換えることができます。

  1. 子プロセスが作成される 直前に Engine.dispose() を呼び出します。これにより、親接続が子プロセスに転送されないようにしながら、子プロセスが新しい接続プールで開始されます:

    engine = create_engine("mysql://user:pass@host/dbname")
    
    def run_in_process():
        with engine.connect() as conn:
            conn.execute(text("..."))
    
    # before process starts, ensure engine.dispose() is called
    engine.dispose()
    p = Process(target=run_in_process)
    p.start()
  1. プロセス境界を越えて共有されている接続をテストし、それらを無効にするイベントハンドラを接続プールに適用できます。:

    from sqlalchemy import event
    from sqlalchemy import exc
    import os
    
    engine = create_engine("...")
    
    @event.listens_for(engine, "connect")
    def connect(dbapi_connection, connection_record):
        connection_record.info["pid"] = os.getpid()
    
    @event.listens_for(engine, "checkout")
    def checkout(dbapi_connection, connection_record, connection_proxy):
        pid = os.getpid()
        if connection_record.info["pid"] != pid:
            connection_record.dbapi_connection = connection_proxy.dbapi_connection = None
            raise exc.DisconnectionError(
                "Connection record belongs to pid %s, "
                "attempting to check out in pid %s" % (connection_record.info["pid"], pid)
            )

    上記では、 Disconnect Handling - Pessimistic で説明されているのと同様のアプローチを使用して、別の親プロセスから発信されたDBAPI接続を “無効な” 接続として扱い、新しい接続を作成するために接続レコードをリサイクルするようプールに強制します。

上記の方法は、プロセス間で共有されている Engine の場合に対応します。プロセス境界を越えて特定の Connection を共有する場合には、上記の手順だけでは十分ではありません。特定の Connection のスコープを単一のプロセス(およびスレッド)に対してローカルにしておきたいのです。さらに、トランザクションを開始し、アクティブな Connection インスタンスを参照するanORM Session オブジェクトのように、進行中のトランザクション状態をプロセス境界を越えて直接共有することもサポートされていません。ここでも、新しいプロセスで新しい Session オブジェクトを作成したいのです。

Using a pool instance directly

プールの実装は、エンジンなしで直接使用できます。これは、他のSQLAlchemy機能なしでプールの動作を使用したいアプリケーションで使用できます。以下の例では、 create_pool_from_url() を使用して、 MySQLdb ダイアレクトのデフォルトのプールを取得しています:

from sqlalchemy import create_pool_from_url

my_pool = create_pool_from_url(
    "mysql+mysqldb://", max_overflow=5, pool_size=5, pre_ping=True
)

con = my_pool.connect()
# use the connection
...
# then close it
con.close()

作成するプールのタイプが指定されていない場合は、デフォルトのものが使用されます。直接指定するには、次の例のように引数 poolclass を使用します。:

from sqlalchemy import create_pool_from_url
from sqlalchemy import NullPool

my_pool = create_pool_from_url("mysql+mysqldb://", poolclass=NullPool)

API Documentation - Available Pool Implementations

Object Name Description

_ConnectionFairy

Proxies a DBAPI connection and provides return-on-dereference support.

_ConnectionRecord

Maintains a position in a connection pool which references a pooled connection.

AssertionPool

A Pool that allows at most one checked out connection at any given time.

AsyncAdaptedQueuePool

An asyncio-compatible version of QueuePool.

ConnectionPoolEntry

Interface for the object that maintains an individual database connection on behalf of a Pool instance.

ManagesConnection

Common base for the two connection-management interfaces PoolProxiedConnection and ConnectionPoolEntry.

NullPool

A Pool which does not pool connections.

Pool

Abstract base class for connection pools.

PoolProxiedConnection

A connection-like adapter for a PEP 249 DBAPI connection, which includes additional methods specific to the Pool implementation.

QueuePool

A Pool that imposes a limit on the number of open connections.

SingletonThreadPool

A Pool that maintains one connection per thread.

StaticPool

A Pool of exactly one connection, used for all requests.

class sqlalchemy.pool.Pool

Abstract base class for connection pools.

Class signature

class sqlalchemy.pool.Pool (sqlalchemy.log.Identified, sqlalchemy.event.registry.EventTarget)

method sqlalchemy.pool.Pool.__init__(creator: _CreatorFnType | _CreatorWRecFnType, recycle: int = -1, echo: log._EchoFlagType = None, logging_name: str | None = None, reset_on_return: _ResetStyleArgType = True, events: List[Tuple[_ListenerFnType, str]] | None = None, dialect: _ConnDialect | Dialect | None = None, pre_ping: bool = False, _dispatch: _DispatchCommon[Pool] | None = None)

Construct a Pool.

Parameters:
  • creator – a callable function that returns a DB-API connection object. The function will be called with parameters.

  • recycle – If set to a value other than -1, number of seconds between connection recycling, which means upon checkout, if this timeout is surpassed the connection will be closed and replaced with a newly opened connection. Defaults to -1.

  • logging_name – String identifier which will be used within the “name” field of logging records generated within the “sqlalchemy.pool” logger. Defaults to a hexstring of the object’s id.

  • echo

    if True, the connection pool will log informational output such as when connections are invalidated as well as when connections are recycled to the default log handler, which defaults to sys.stdout for output.. If set to the string "debug", the logging will include pool checkouts and checkins.

    The Pool.echo parameter can also be set from the create_engine() call by using the create_engine.echo_pool parameter.

    See also

    Configuring Logging - further detail on how to configure logging.

  • reset_on_return

    Determine steps to take on connections as they are returned to the pool, which were not otherwise handled by a Connection. Available from create_engine() via the create_engine.pool_reset_on_return parameter.

    Pool.reset_on_return can have any of these values:

    • "rollback" - call rollback() on the connection, to release locks and transaction resources. This is the default value. The vast majority of use cases should leave this value set.

    • "commit" - call commit() on the connection, to release locks and transaction resources. A commit here may be desirable for databases that cache query plans if a commit is emitted, such as Microsoft SQL Server. However, this value is more dangerous than ‘rollback’ because any data changes present on the transaction are committed unconditionally.

    • None - don’t do anything on the connection. This setting may be appropriate if the database / DBAPI works in pure “autocommit” mode at all times, or if a custom reset handler is established using the PoolEvents.reset() event handler.

    • True - same as ‘rollback’, this is here for backwards compatibility.

    • False - same as None, this is here for backwards compatibility.

    For further customization of reset on return, the PoolEvents.reset() event hook may be used which can perform any connection activity desired on reset.

  • events – a list of 2-tuples, each of the form (callable, target) which will be passed to listen() upon construction. Provided here so that event listeners can be assigned via create_engine() before dialect-level listeners are applied.

  • dialect – a Dialect that will handle the job of calling rollback(), close(), or commit() on DBAPI connections. If omitted, a built-in “stub” dialect is used. Applications that make use of create_engine() should not use this parameter as it is handled by the engine creation strategy.

  • pre_ping

    if True, the pool will emit a “ping” (typically “SELECT 1”, but is dialect-specific) on the connection upon checkout, to test if the connection is alive or not. If not, the connection is transparently re-connected and upon success, all other pooled connections established prior to that timestamp are invalidated. Requires that a dialect is passed as well to interpret the disconnection error.

    New in version 1.2.

method sqlalchemy.pool.Pool.connect() PoolProxiedConnection

Return a DBAPI connection from the pool.

The connection is instrumented such that when its close() method is called, the connection will be returned to the pool.

method sqlalchemy.pool.Pool.dispose() None

Dispose of this pool.

This method leaves the possibility of checked-out connections remaining open, as it only affects connections that are idle in the pool.

See also

Pool.recreate()

method sqlalchemy.pool.Pool.recreate() Pool

Return a new Pool, of the same class as this one and configured with identical creation arguments.

This method is used in conjunction with dispose() to close out an entire Pool and create a new one in its place.

class sqlalchemy.pool.QueuePool

A Pool that imposes a limit on the number of open connections.

QueuePool is the default pooling implementation used for all Engine objects other than SQLite with a :memory: database.

The QueuePool class is not compatible with asyncio and create_async_engine(). The AsyncAdaptedQueuePool class is used automatically when using create_async_engine(), if no other kind of pool is specified.

method sqlalchemy.pool.QueuePool.__init__(creator: _CreatorFnType | _CreatorWRecFnType, pool_size: int = 5, max_overflow: int = 10, timeout: float = 30.0, use_lifo: bool = False, **kw: Any)

Construct a QueuePool.

Parameters:
  • creator – a callable function that returns a DB-API connection object, same as that of Pool.creator.

  • pool_size – The size of the pool to be maintained, defaults to 5. This is the largest number of connections that will be kept persistently in the pool. Note that the pool begins with no connections; once this number of connections is requested, that number of connections will remain. pool_size can be set to 0 to indicate no size limit; to disable pooling, use a NullPool instead.

  • max_overflow – The maximum overflow size of the pool. When the number of checked-out connections reaches the size set in pool_size, additional connections will be returned up to this limit. When those additional connections are returned to the pool, they are disconnected and discarded. It follows then that the total number of simultaneous connections the pool will allow is pool_size + max_overflow, and the total number of “sleeping” connections the pool will allow is pool_size. max_overflow can be set to -1 to indicate no overflow limit; no limit will be placed on the total number of concurrent connections. Defaults to 10.

  • timeout – The number of seconds to wait before giving up on returning a connection. Defaults to 30.0. This can be a float but is subject to the limitations of Python time functions which may not be reliable in the tens of milliseconds.

  • use_lifo

    use LIFO (last-in-first-out) when retrieving connections instead of FIFO (first-in-first-out). Using LIFO, a server-side timeout scheme can reduce the number of connections used during non-peak periods of use. When planning for server-side timeouts, ensure that a recycle or pre-ping strategy is in use to gracefully handle stale connections.

    New in version 1.3.

  • **kw – Other keyword arguments including Pool.recycle, Pool.echo, Pool.reset_on_return and others are passed to the Pool constructor.

method sqlalchemy.pool.QueuePool.dispose() None

Dispose of this pool.

This method leaves the possibility of checked-out connections remaining open, as it only affects connections that are idle in the pool.

See also

Pool.recreate()

method sqlalchemy.pool.QueuePool.recreate() QueuePool

Return a new Pool, of the same class as this one and configured with identical creation arguments.

This method is used in conjunction with dispose() to close out an entire Pool and create a new one in its place.

class sqlalchemy.pool.AsyncAdaptedQueuePool

An asyncio-compatible version of QueuePool.

This pool is used by default when using AsyncEngine engines that were generated from create_async_engine(). It uses an asyncio-compatible queue implementation that does not use threading.Lock.

The arguments and operation of AsyncAdaptedQueuePool are otherwise identical to that of QueuePool.

class sqlalchemy.pool.SingletonThreadPool

A Pool that maintains one connection per thread.

Maintains one connection per each thread, never moving a connection to a thread other than the one which it was created in.

Warning

the SingletonThreadPool will call .close() on arbitrary connections that exist beyond the size setting of pool_size, e.g. if more unique thread identities than what pool_size states are used. This cleanup is non-deterministic and not sensitive to whether or not the connections linked to those thread identities are currently in use.

SingletonThreadPool may be improved in a future release, however in its current status it is generally used only for test scenarios using a SQLite :memory: database and is not recommended for production use.

The SingletonThreadPool class is not compatible with asyncio and create_async_engine().

Options are the same as those of Pool, as well as:

Parameters:

pool_size – The number of threads in which to maintain connections at once. Defaults to five.

SingletonThreadPool is used by the SQLite dialect automatically when a memory-based database is used. See SQLite.

method sqlalchemy.pool.SingletonThreadPool.connect() PoolProxiedConnection

Return a DBAPI connection from the pool.

The connection is instrumented such that when its close() method is called, the connection will be returned to the pool.

method sqlalchemy.pool.SingletonThreadPool.dispose() None

Dispose of this pool.

method sqlalchemy.pool.SingletonThreadPool.recreate() SingletonThreadPool

Return a new Pool, of the same class as this one and configured with identical creation arguments.

This method is used in conjunction with dispose() to close out an entire Pool and create a new one in its place.

class sqlalchemy.pool.AssertionPool

A Pool that allows at most one checked out connection at any given time.

This will raise an exception if more than one connection is checked out at a time. Useful for debugging code that is using more connections than desired.

The AssertionPool class is compatible with asyncio and create_async_engine().

method sqlalchemy.pool.AssertionPool.dispose() None

Dispose of this pool.

This method leaves the possibility of checked-out connections remaining open, as it only affects connections that are idle in the pool.

See also

Pool.recreate()

method sqlalchemy.pool.AssertionPool.recreate() AssertionPool

Return a new Pool, of the same class as this one and configured with identical creation arguments.

This method is used in conjunction with dispose() to close out an entire Pool and create a new one in its place.

class sqlalchemy.pool.NullPool

A Pool which does not pool connections.

Instead it literally opens and closes the underlying DB-API connection per each connection open/close.

Reconnect-related functions such as recycle and connection invalidation are not supported by this Pool implementation, since no connections are held persistently.

The NullPool class is compatible with asyncio and create_async_engine().

method sqlalchemy.pool.NullPool.dispose() None

Dispose of this pool.

This method leaves the possibility of checked-out connections remaining open, as it only affects connections that are idle in the pool.

See also

Pool.recreate()

method sqlalchemy.pool.NullPool.recreate() NullPool

Return a new Pool, of the same class as this one and configured with identical creation arguments.

This method is used in conjunction with dispose() to close out an entire Pool and create a new one in its place.

class sqlalchemy.pool.StaticPool

A Pool of exactly one connection, used for all requests.

Reconnect-related functions such as recycle and connection invalidation (which is also used to support auto-reconnect) are only partially supported right now and may not yield good results.

The StaticPool class is compatible with asyncio and create_async_engine().

method sqlalchemy.pool.StaticPool.dispose() None

Dispose of this pool.

This method leaves the possibility of checked-out connections remaining open, as it only affects connections that are idle in the pool.

See also

Pool.recreate()

method sqlalchemy.pool.StaticPool.recreate() StaticPool

Return a new Pool, of the same class as this one and configured with identical creation arguments.

This method is used in conjunction with dispose() to close out an entire Pool and create a new one in its place.

class sqlalchemy.pool.ManagesConnection

Common base for the two connection-management interfaces PoolProxiedConnection and ConnectionPoolEntry.

These two objects are typically exposed in the public facing API via the connection pool event hooks, documented at PoolEvents.

New in version 2.0.

attribute sqlalchemy.pool.ManagesConnection.dbapi_connection: DBAPIConnection | None

A reference to the actual DBAPI connection being tracked.

This is a PEP 249-compliant object that for traditional sync-style dialects is provided by the third-party DBAPI implementation in use. For asyncio dialects, the implementation is typically an adapter object provided by the SQLAlchemy dialect itself; the underlying asyncio object is available via the ManagesConnection.driver_connection attribute.

SQLAlchemy’s interface for the DBAPI connection is based on the DBAPIConnection protocol object

attribute sqlalchemy.pool.ManagesConnection.driver_connection: Any | None

The “driver level” connection object as used by the Python DBAPI or database driver.

For traditional PEP 249 DBAPI implementations, this object will be the same object as that of ManagesConnection.dbapi_connection. For an asyncio database driver, this will be the ultimate “connection” object used by that driver, such as the asyncpg.Connection object which will not have standard pep-249 methods.

New in version 1.4.24.

attribute sqlalchemy.pool.ManagesConnection.info

Info dictionary associated with the underlying DBAPI connection referred to by this ManagesConnection instance, allowing user-defined data to be associated with the connection.

The data in this dictionary is persistent for the lifespan of the DBAPI connection itself, including across pool checkins and checkouts. When the connection is invalidated and replaced with a new one, this dictionary is cleared.

For a PoolProxiedConnection instance that’s not associated with a ConnectionPoolEntry, such as if it were detached, the attribute returns a dictionary that is local to that ConnectionPoolEntry. Therefore the ManagesConnection.info attribute will always provide a Python dictionary.

method sqlalchemy.pool.ManagesConnection.invalidate(e: BaseException | None = None, soft: bool = False) None

Mark the managed connection as invalidated.

Parameters:
  • e – an exception object indicating a reason for the invalidation.

  • soft – if True, the connection isn’t closed; instead, this connection will be recycled on next checkout.

attribute sqlalchemy.pool.ManagesConnection.record_info

Persistent info dictionary associated with this ManagesConnection.

Unlike the ManagesConnection.info dictionary, the lifespan of this dictionary is that of the ConnectionPoolEntry which owns it; therefore this dictionary will persist across reconnects and connection invalidation for a particular entry in the connection pool.

For a PoolProxiedConnection instance that’s not associated with a ConnectionPoolEntry, such as if it were detached, the attribute returns None. Contrast to the ManagesConnection.info dictionary which is never None.

class sqlalchemy.pool.ConnectionPoolEntry

Interface for the object that maintains an individual database connection on behalf of a Pool instance.

The ConnectionPoolEntry object represents the long term maintainance of a particular connection for a pool, including expiring or invalidating that connection to have it replaced with a new one, which will continue to be maintained by that same ConnectionPoolEntry instance. Compared to PoolProxiedConnection, which is the short-term, per-checkout connection manager, this object lasts for the lifespan of a particular “slot” within a connection pool.

The ConnectionPoolEntry object is mostly visible to public-facing API code when it is delivered to connection pool event hooks, such as PoolEvents.connect() and PoolEvents.checkout().

New in version 2.0: ConnectionPoolEntry provides the public facing interface for the _ConnectionRecord internal class.

method sqlalchemy.pool.ConnectionPoolEntry.close() None

Close the DBAPI connection managed by this connection pool entry.

attribute sqlalchemy.pool.ConnectionPoolEntry.dbapi_connection: DBAPIConnection | None

A reference to the actual DBAPI connection being tracked.

This is a PEP 249-compliant object that for traditional sync-style dialects is provided by the third-party DBAPI implementation in use. For asyncio dialects, the implementation is typically an adapter object provided by the SQLAlchemy dialect itself; the underlying asyncio object is available via the ManagesConnection.driver_connection attribute.

SQLAlchemy’s interface for the DBAPI connection is based on the DBAPIConnection protocol object

attribute sqlalchemy.pool.ConnectionPoolEntry.driver_connection: Any | None

The “driver level” connection object as used by the Python DBAPI or database driver.

For traditional PEP 249 DBAPI implementations, this object will be the same object as that of ManagesConnection.dbapi_connection. For an asyncio database driver, this will be the ultimate “connection” object used by that driver, such as the asyncpg.Connection object which will not have standard pep-249 methods.

New in version 1.4.24.

attribute sqlalchemy.pool.ConnectionPoolEntry.in_use

Return True the connection is currently checked out

attribute sqlalchemy.pool.ConnectionPoolEntry.info

inherited from the ManagesConnection.info attribute of ManagesConnection

Info dictionary associated with the underlying DBAPI connection referred to by this ManagesConnection instance, allowing user-defined data to be associated with the connection.

The data in this dictionary is persistent for the lifespan of the DBAPI connection itself, including across pool checkins and checkouts. When the connection is invalidated and replaced with a new one, this dictionary is cleared.

For a PoolProxiedConnection instance that’s not associated with a ConnectionPoolEntry, such as if it were detached, the attribute returns a dictionary that is local to that ConnectionPoolEntry. Therefore the ManagesConnection.info attribute will always provide a Python dictionary.

method sqlalchemy.pool.ConnectionPoolEntry.invalidate(e: BaseException | None = None, soft: bool = False) None

inherited from the ManagesConnection.invalidate() method of ManagesConnection

Mark the managed connection as invalidated.

Parameters:
  • e – an exception object indicating a reason for the invalidation.

  • soft – if True, the connection isn’t closed; instead, this connection will be recycled on next checkout.

attribute sqlalchemy.pool.ConnectionPoolEntry.record_info

inherited from the ManagesConnection.record_info attribute of ManagesConnection

Persistent info dictionary associated with this ManagesConnection.

Unlike the ManagesConnection.info dictionary, the lifespan of this dictionary is that of the ConnectionPoolEntry which owns it; therefore this dictionary will persist across reconnects and connection invalidation for a particular entry in the connection pool.

For a PoolProxiedConnection instance that’s not associated with a ConnectionPoolEntry, such as if it were detached, the attribute returns None. Contrast to the ManagesConnection.info dictionary which is never None.

class sqlalchemy.pool.PoolProxiedConnection

A connection-like adapter for a PEP 249 DBAPI connection, which includes additional methods specific to the Pool implementation.

PoolProxiedConnection is the public-facing interface for the internal _ConnectionFairy implementation object; users familiar with _ConnectionFairy can consider this object to be equivalent.

New in version 2.0: PoolProxiedConnection provides the public- facing interface for the _ConnectionFairy internal class.

method sqlalchemy.pool.PoolProxiedConnection.close() None

Release this connection back to the pool.

The PoolProxiedConnection.close() method shadows the PEP 249 .close() method, altering its behavior to instead release the proxied connection back to the connection pool.

Upon release to the pool, whether the connection stays “opened” and pooled in the Python process, versus actually closed out and removed from the Python process, is based on the pool implementation in use and its configuration and current state.

attribute sqlalchemy.pool.PoolProxiedConnection.dbapi_connection: DBAPIConnection | None

A reference to the actual DBAPI connection being tracked.

This is a PEP 249-compliant object that for traditional sync-style dialects is provided by the third-party DBAPI implementation in use. For asyncio dialects, the implementation is typically an adapter object provided by the SQLAlchemy dialect itself; the underlying asyncio object is available via the ManagesConnection.driver_connection attribute.

SQLAlchemy’s interface for the DBAPI connection is based on the DBAPIConnection protocol object

method sqlalchemy.pool.PoolProxiedConnection.detach() None

Separate this connection from its Pool.

This means that the connection will no longer be returned to the pool when closed, and will instead be literally closed. The associated ConnectionPoolEntry is de-associated from this DBAPI connection.

Note that any overall connection limiting constraints imposed by a Pool implementation may be violated after a detach, as the detached connection is removed from the pool’s knowledge and control.

attribute sqlalchemy.pool.PoolProxiedConnection.driver_connection: Any | None

The “driver level” connection object as used by the Python DBAPI or database driver.

For traditional PEP 249 DBAPI implementations, this object will be the same object as that of ManagesConnection.dbapi_connection. For an asyncio database driver, this will be the ultimate “connection” object used by that driver, such as the asyncpg.Connection object which will not have standard pep-249 methods.

New in version 1.4.24.

attribute sqlalchemy.pool.PoolProxiedConnection.info

inherited from the ManagesConnection.info attribute of ManagesConnection

Info dictionary associated with the underlying DBAPI connection referred to by this ManagesConnection instance, allowing user-defined data to be associated with the connection.

The data in this dictionary is persistent for the lifespan of the DBAPI connection itself, including across pool checkins and checkouts. When the connection is invalidated and replaced with a new one, this dictionary is cleared.

For a PoolProxiedConnection instance that’s not associated with a ConnectionPoolEntry, such as if it were detached, the attribute returns a dictionary that is local to that ConnectionPoolEntry. Therefore the ManagesConnection.info attribute will always provide a Python dictionary.

method sqlalchemy.pool.PoolProxiedConnection.invalidate(e: BaseException | None = None, soft: bool = False) None

inherited from the ManagesConnection.invalidate() method of ManagesConnection

Mark the managed connection as invalidated.

Parameters:
  • e – an exception object indicating a reason for the invalidation.

  • soft – if True, the connection isn’t closed; instead, this connection will be recycled on next checkout.

attribute sqlalchemy.pool.PoolProxiedConnection.is_detached

Return True if this PoolProxiedConnection is detached from its pool.

attribute sqlalchemy.pool.PoolProxiedConnection.is_valid

Return True if this PoolProxiedConnection still refers to an active DBAPI connection.

attribute sqlalchemy.pool.PoolProxiedConnection.record_info

inherited from the ManagesConnection.record_info attribute of ManagesConnection

Persistent info dictionary associated with this ManagesConnection.

Unlike the ManagesConnection.info dictionary, the lifespan of this dictionary is that of the ConnectionPoolEntry which owns it; therefore this dictionary will persist across reconnects and connection invalidation for a particular entry in the connection pool.

For a PoolProxiedConnection instance that’s not associated with a ConnectionPoolEntry, such as if it were detached, the attribute returns None. Contrast to the ManagesConnection.info dictionary which is never None.

class sqlalchemy.pool._ConnectionFairy

Proxies a DBAPI connection and provides return-on-dereference support.

This is an internal object used by the Pool implementation to provide context management to a DBAPI connection delivered by that Pool. The public facing interface for this class is described by the PoolProxiedConnection class. See that class for public API details.

The name “fairy” is inspired by the fact that the _ConnectionFairy object’s lifespan is transitory, as it lasts only for the length of a specific DBAPI connection being checked out from the pool, and additionally that as a transparent proxy, it is mostly invisible.

Class signature

class sqlalchemy.pool._ConnectionFairy (sqlalchemy.pool.base.PoolProxiedConnection)

class sqlalchemy.pool._ConnectionRecord

Maintains a position in a connection pool which references a pooled connection.

This is an internal object used by the Pool implementation to provide context management to a DBAPI connection maintained by that Pool. The public facing interface for this class is described by the ConnectionPoolEntry class. See that class for public API details.

Class signature

class sqlalchemy.pool._ConnectionRecord (sqlalchemy.pool.base.ConnectionPoolEntry)