SqlAlchemy-2-0-中文文档-二十七-
SqlAlchemy 2.0 中文文档(二十七)
连接池
连接池是一种标准技术,用于在内存中维护长时间运行的连接以进行有效重用,并为应用程序可能同时使用的连接总数提供管理。
特别是对于服务器端 Web 应用程序,连接池是在内存中维护一组活动数据库连接并在请求之间重用的标准方式。
SQLAlchemy 包含几种连接池实现,它们与Engine集成。它们也可以直接用于希望为其他普通 DBAPI 方法添加连接池的应用程序。
连接池配置
create_engine() 函数返回的 Engine 大多数情况下都已集成了一个 QueuePool,预先配置了合理的池默认值。如果你只是想学习如何启用连接池 - 恭喜!你已经完成了。
最常见的 QueuePool 调整参数可以直接作为关键字参数传递给 create_engine():pool_size、max_overflow、pool_recycle 和 pool_timeout。例如:
engine = create_engine(
"postgresql+psycopg2://me@localhost/mydb", pool_size=20, max_overflow=0
)
所有 SQLAlchemy 连接池实现的共同点是它们都不会“预先创建”连接 - 所有实现都会等待首次使用之前才创建连接。在那时,如果没有额外的并发检出请求需要更多连接,就不会创建额外的连接。这就是为什么 create_engine() 默认使用大小为五的 QueuePool 是完全可以的,而不管应用程序是否真的需要排队五个连接 - 只有当应用程序实际上同时使用五个连接时,池才会增长到该大小,这种使用小池的行为是完全合适的默认行为。
注意
QueuePool类不兼容 asyncio。当使用create_async_engine创建AsyncEngine实例时,将使用AsyncAdaptedQueuePool类,该类使用与 asyncio 兼容的队列实现。
切换池实现
使用不同类型的池与create_engine()的通常方法是使用poolclass参数。此参数接受从sqlalchemy.pool模块导入的类,并为您处理构建池的详细信息。这里的一个常见用例是禁用连接池,可以通过使用NullPool实现来实现:
from sqlalchemy.pool import NullPool
engine = create_engine(
"postgresql+psycopg2://scott:tiger@localhost/test", poolclass=NullPool
)
使用自定义连接函数
请参阅自定义 DBAPI connect()参数 / on-connect routines 一节,了解各种连接定制例程。
构建池
要单独使用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")
透明代理的目的是拦截close()调用,这样,DBAPI 连接不会关闭,而是返回到池中:
# "close" the connection. Returns
# it to the pool.
conn.close()
当代理被垃圾回收时,它还将其包含的 DBAPI 连接返回到池中,尽管在 Python 中并非确定性地立即发生这种情况(尽管在 cPython 中通常是这样)。然而,不建议使用此用法,特别是不支持与 asyncio DBAPI 驱动程序一起使用。
返回时重置
池包括“返回时重置”行为,当连接返回到池时,将调用 DBAPI 连接的rollback()方法。这样做是为了从连接中删除任何现有的事务状态,这不仅包括未提交的数据,还包括表和行锁。对于大多数 DBAPIs,调用rollback()是廉价的,如果 DBAPI 已经完成了一个事务,则该方法应该是无操作的。
禁用非事务连接的返回时重置
对于一些特定情况下rollback()不起作用的情况,例如使用配置为 autocommit 或使用没有 ACID 功能的数据库(如 MySQL 的 MyISAM 引擎)的连接时,可以禁用归还时重置行为,通常出于性能原因。可以通过使用Pool.reset_on_return参数来实现,该参数也可以从create_engine()中使用create_engine.pool_reset_on_return传递值为None来实现。下面的示例中演示了这一点,结合了AUTOCOMMIT的create_engine.isolation_level参数设置:
non_acid_engine = create_engine(
"mysql://scott:tiger@host/db",
pool_reset_on_return=None,
isolation_level="AUTOCOMMIT",
)
上述引擎在连接返回到池中时实际上不会执行回滚操作;由于启用了 AUTOCOMMIT,驱动程序也不会执行任何 BEGIN 操作。
自定义归还时重置方案
仅包含单个rollback()的“归还时重置”对于某些用例可能不足够;特别是,使用临时表的应用程序可能希望在连接归还时自动删除这些表。一些(但并非所有)后端包括可以在数据库连接范围内“重置”这些表的功能,这可能是连接池重置的理想行为。其他服务器资源,如准备好的语句句柄和服务器端语句缓存,可能会在归还过程之后持续存在,具体取决于具体情况是否希望这样。同样,一些(但再次并非所有)后端可能提供一种重置此状态的方法。已知具有此类重置方案的两个 SQLAlchemy 包含的方言包括 Microsoft SQL Server,其中通常使用一个名为sp_reset_connection的未记录但广为人知的存储过程,以及 PostgreSQL,后者具有一系列良好记录的命令,包括DISCARD、RESET、DEALLOCATE和UNLISTEN。
以下示例说明了如何使用 PoolEvents.reset() 事件钩子将返回时的重置替换为 Microsoft SQL Server 的 sp_reset_connection 存储过程。create_engine.pool_reset_on_return 参数设置为 None,以便自定义方案完全替换默认行为。自定义钩子实现在任何情况下调用 .rollback(),因为通常重要的是 DBAPI 自己的提交/回滚跟事务状态保持一致:
from sqlalchemy import create_engine
from sqlalchemy import event
mssql_engine = create_engine(
"mssql+pyodbc://scott:tiger⁵HHH@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()
自版本 2.0.0b3 起进行了更改:在 PoolEvents.reset() 事件中添加了额外的状态参数,并且确保该事件在所有“重置”发生时都被调用,以便作为自定义“重置”处理程序的适当位置。之前使用 PoolEvents.checkin() 处理程序的方案仍然可用。
另请参阅
-
用于连接池的临时表/资源重置 - 在 Microsoft SQL Server 文档中
-
用于连接池的临时表/资源重置 - 在 PostgreSQL 文档中
记录返回时重置事件
记录池事件,包括返回时重置,可以将其设置为 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
池事件
连接池支持事件接口,允许在第一次连接、每次新连接、以及连接的签出和签入时执行钩子。详情请参阅 PoolEvents。
处理断开连接
连接池具有刷新单个连接以及其整套连接的能力,将先前池化的连接设置为“无效”。常见用例是在数据库服务器重新启动时允许连接池优雅地恢复,并且所有先前建立的连接都不再可用。有两种方法可以做到这一点。
断开连接处理 - 悲观
悲观方法是指在每次连接池检出时发出 SQL 连接上的测试语句,以测试数据库连接是否仍然可行。该实现是方言特定的,并且利用特定于 DBAPI 的 ping 方法,或者使用简单的 SQL 语句如“SELECT 1”,以便测试连接的活动性。
该方法会在连接检出过程中增加一小部分额外开销,但除此之外,它是完全消除因连接池中的过期连接而导致数据库错误的最简单和可靠的方法。调用应用程序无需担心组织操作以从池中恢复过期连接。
可以通过使用Pool.pre_ping参数来实现对连接的悲观检测,该参数可通过create_engine()的create_engine.pool_pre_ping参数获得:
engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)
“预 ping”功能根据每个方言的基础,通过调用特定于 DBAPI 的“ping”方法,或者如果不可用,则发出与“SELECT 1”等效的 SQL,捕获任何错误并将错误检测为“断开”情况。如果 ping/错误检查确定连接不可用,则连接将立即被重新使用,并且所有比当前时间更早的其他池连接都将无效,以便下次检出时它们也将在使用前被重新使用。
如果数据库在“预 ping”运行时仍然不可用,则初始连接将失败,并且无法连接的错误将正常传播。在数据库可用于连接但无法响应“ping”的情况下,将在放弃之前尝试最多三次“pre_ping”,并传播最后收到的数据库错误。
需要特别注意的是,预检测方法不适用于事务中断开连接或其他 SQL 操作的情况。如果数据库在事务进行中变得不可用,则事务将丢失并引发数据库错误。虽然Connection对象会检测到“断开连接”情况并重新使用连接以及在此情况发生时使其余连接池失效,但引发异常的单个操作将丢失,并且由应用程序来放弃操作或重新尝试整个事务。如果引擎使用 DBAPI 级别的自动提交连接配置,如设置事务隔离级别,包括 DBAPI 自动提交,则可能会使用事件在操作中透明地重新连接。有关示例,请参阅如何“自动重试”语句执行?。
对于使用“SELECT 1”并捕获错误以检测断开连接的方言,可以使用DialectEvents.handle_error()钩子为新的后端特定错误消息增加断开连接测试。
自定义 / 传统悲观 Ping
在create_engine.pool_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
以上方法的优点在于,我们利用了 SQLAlchemy 检测那些已知指示“断开连接”情况的 DBAPI 异常的设施,以及Engine对象在此情况发生时正确使当前连接池失效并允许当前Connection重新验证到新的 DBAPI 连接。
断开连接处理 - 乐观
当不采用悲观处理时,以及当数据库在事务中使用连接期间关闭和/或重新启动时,处理陈旧/关闭连接的另一种方法是让 SQLAlchemy 在发生断开连接时处理它们,在这时,池中的所有连接都被标记为无效,这意味着它们被认为是陈旧的,并将在下次检出时刷新。此行为假定Pool与Engine一起使用。Engine具有可以检测到断开连接事件并自动刷新池的逻辑。
当Connection尝试使用 DBAPI 连接,并且引发与“断开连接”事件相对应的异常时,连接将被标记为无效。然后,Connection调用Pool.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"))
上面的示例说明,在检测到断开连接事件后,无需任何特殊干预即可刷新池,池会继续正常运行。但是,对于每个在数据库不可用事件发生时处于使用状态的连接,都会引发一个数据库异常。在使用 ORM 会话的典型 Web 应用程序中,上述条件将对应于请求失败并出现 500 错误,然后 Web 应用程序在那之后正常继续。因此,该方法是“乐观”的,因为不会预期频繁的数据库重启。
设置池回收
可以增强“乐观”方法的附加设置是设置池回收参数。此参数防止池使用已经过一定时期的特定连接,并且适用于自动在一段时间后关闭失效连接的数据库后端,例如 MySQL:
from sqlalchemy import create_engine
e = create_engine("mysql+mysqldb://scott:tiger@localhost/test", pool_recycle=3600)
以上,任何已打开超过一小时的 DBAPI 连接将在下次检出时被标记为无效并替换。请注意,这种无效化仅发生在检出时 - 不会发生在任何处于已检出状态的连接上。pool_recycle是Pool本身的一个函数,独立于是否正在使用Engine。### 更多关于无效化的内容
Pool提供了“连接失效”服务,允许显式无效连接以及响应确定使连接无法使用的条件自动无效连接。
“失效”意味着特定的 DBAPI 连接从池中移除并丢弃。如果不清楚连接本身是否已关闭,则会调用此连接的.close()方法,但是如果此方法失败,则会记录异常但操作仍将继续。
当使用Engine时,Connection.invalidate()方法是显式无效的通常入口点。导致 DBAPI 连接失效的其他条件包括:
-
当调用诸如
connection.execute()之类的方法时引发 DBAPI 异常,比如OperationalError,则被检测为所谓的“断开连接”条件。由于 Python DBAPI 没有提供用于确定异常性质的标准系统,因此所有的 SQLAlchemy 方言都包括一个名为is_disconnect()的系统,该系统将检查异常对象的内容,包括字符串消息和其中包含的任何潜在错误代码,以确定此异常是否表明连接不再可用。如果是这种情况,则调用_ConnectionFairy.invalidate()方法,然后丢弃 DBAPI 连接。 -
当连接返回到池中,并且调用连接的
connection.rollback()或connection.commit()方法,根据池的“重置返回”行为,抛出异常。将尝试最终调用.close()关闭连接,然后丢弃它。 -
当实现
PoolEvents.checkout()的监听器引发DisconnectionError异常时,表示连接无法使用,需要进行新的连接尝试。
所有发生的失效都将调用PoolEvents.invalidate()事件。 ### 支持断开连接情况的新数据库错误代码
SQLAlchemy 方言每个都包含一个名为 is_disconnect() 的例程,当遇到 DBAPI 异常时会调用它。DBAPI 异常对象被传递到这个方法,在那里方言特定的启发法则将确定接收到的错误代码是否表明数据库连接已被“断开”,或者处于其他不可用状态,这表明它应该被回收利用。在这里应用的启发法则可以使用 DialectEvents.handle_error() 事件钩子进行定制,该事件钩子通常通过所属的 Engine 对象建立。使用这个钩子,发生的所有错误都将传递一个称为 ExceptionContext 的上下文对象。自定义事件钩子可以控制是否应该将特定错误视为“断开”情况,以及是否应该导致整个连接池无效。
例如,为了添加支持将 Oracle 错误代码 DPY-1001 和 DPY-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 错误被引发时调用,包括那些在使用 池预 ping 功能时捕获的错误,用于依赖于断开错误处理的后端(在 2.0 中新增)。
另请参见
DialectEvents.handle_error() ## 使用 FIFO vs. LIFO
QueuePool 类包含一个名为 QueuePool.use_lifo 的标志,该标志也可以通过 create_engine() 中的标志 create_engine.pool_use_lifo 进行访问。将此标志设置为 True 会导致池的“队列”行为变为“堆栈”行为,例如,返回到池的最后一个连接将在下一次请求时首先使用。与池的先入先出长期行为相反,即产生池中每个连接的循环效果,LIFO 模式允许多余的连接在池中保持空闲,从而允许服务器端超时方案关闭这些连接。FIFO 和 LIFO 之间的区别基本上是池是否在空闲期间保持完整的连接集:
engine = create_engine("postgreql://", pool_use_lifo=True, pool_pre_ping=True)
上面,我们还使用 create_engine.pool_pre_ping 标志,以便服务器端关闭的连接能够被连接池优雅地处理,并替换为新连接。
注意该标志仅适用于 QueuePool 使用。
在版本 1.3 中新增。
另请参阅
处理断开连接 ## 使用连接池与多进程或 os.fork()
当使用连接池时,以及当使用通过 create_engine() 创建的 Engine 时,至关重要的是,池化的连接不会共享到一个分叉的进程。TCP 连接被表示为文件描述符,通常跨越进程边界工作,这意味着这将导致两个或更多完全独立的 Python 解释器状态代表的文件描述符被并发访问。
根据驱动程序和操作系统的具体情况,此处出现的问题范围从无法工作的连接到被多个进程同时使用的套接字连接,导致消息传递中断(后一种情况通常最常见)。
SQLAlchemy Engine 对象指的是一组现有数据库连接的连接池。因此,当这个对象被复制到子进程时,目标是确保没有数据库连接被传递过去。有四种常用的方法:
-
使用
NullPool禁用连接池。这是最简单的、一次性系统,防止Engine多次使用任何连接:from sqlalchemy.pool import NullPool engine = create_engine("mysql+mysqldb://user:pass@host/dbname", poolclass=NullPool) -
在子进程的初始化阶段,对任何给定的
Engine调用Engine.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)在版本 1.4.33 中新增:添加了
Engine.dispose.close参数,允许在子进程中替换连接池而不会干扰父进程使用的连接。 -
在创建子进程之前直接调用
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() -
可以应用于连接池的事件处理程序来测试跨进程边界共享的连接,并使其失效。
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实例的 ORM Session对象;同样,最好在新进程中创建新的Session对象。
直接使用池实例
可以直接使用池实现而不需要引擎。这可用于只希望使用池行为而不需要所有其他 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 文档 - 可用的池实现
| 对象名称 | 描述 |
|---|---|
| _ConnectionFairy | 代理一个 DBAPI 连接并提供对解除引用的支持。 |
| _ConnectionRecord | 维护连接池中的位置,引用一个池化连接。 |
| AssertionPool | 允许同时最多检出一个连接的Pool。 |
| AsyncAdaptedQueuePool | QueuePool的一个与 asyncio 兼容的版本。 |
| ConnectionPoolEntry | 代表Pool实例上的单个数据库连接的对象的接口。 |
| ManagesConnection | 两个连接管理接口PoolProxiedConnection和ConnectionPoolEntry的通用基类。 |
| NullPool | 不池化连接的连接池。 |
| Pool | 连接池的抽象基类。 |
| PoolProxiedConnection | 一个用于PEP 249 DBAPI 连接的类似连接适配器,包括特定于Pool实现的附加方法。 |
| QueuePool | 对打开连接数量施加限制的Pool。 |
| SingletonThreadPool | 一个每个线程维护一个连接的连接池。 |
| StaticPool | 一个连接池,用于所有请求的一个连接。 |
class sqlalchemy.pool.Pool
连接池的抽象基类。
成员
init(), connect(), dispose(), recreate()
类签名
类sqlalchemy.pool.Pool (sqlalchemy.log.Identified, sqlalchemy.event.registry.EventTarget)
method __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)
构造一个连接池。
参数:
-
creator– 一个可调用的函数,返回一个 DB-API 连接对象。该函数将使用参数调用。 -
recycle– 如果设置为除-1 之外的值,连接回收之间的秒数,这意味着在签出时,如果超过此超时,则连接将被关闭并替换为新打开的连接。默认为-1。 -
logging_name– 将在“sqlalchemy.pool”记录器中生成的日志记录的“name”字段中使用的字符串标识符。默认为对象的 id 的十六进制字符串。 -
echo–如果为 True,连接池将记录信息输出,例如当连接无效时以及当连接被回收到默认日志处理程序时,该处理程序默认为
sys.stdout输出。如果设置为字符串"debug",日志将包括池的签出和签入。Pool.echo参数也可以通过在create_engine()调用中使用create_engine.echo_pool参数进行设置。另请参阅
配置日志记录 - 关于如何配置日志记录的更多详细信息。
-
reset_on_return–确定在连接被返回到池中时需要采取的步骤,这些步骤不会被
Connection以外的方式处理。可通过create_engine()中的create_engine.pool_reset_on_return参数获得。Pool.reset_on_return可以具有以下任一值:-
"rollback"- 在连接上调用 rollback(),以释放锁定和事务资源。这是默认值。绝大多数用例应该保持此值设置。 -
"commit"- 在连接上调用 commit(),以释放锁定和事务资源。如果发出了 commit,这里可能对缓存查询计划的数据库(如 Microsoft SQL Server)是有利的。但是,这个值比‘rollback’更危险,因为事务上的任何数据更改都会无条件提交。 -
None- 在连接上不执行任何操作。如果数据库/DBAPI 始终以纯“自动提交”模式工作,或者如果使用PoolEvents.reset()事件处理程序建立了自定义重置处理程序,则此设置可能是合适的。 -
True- 与‘rollback’相同,这是为了向后兼容而存在的。 -
False- 与 None 相同,这是为了向后兼容而存在的。
要进一步定制重置操作,可以使用
PoolEvents.reset()事件钩子,该钩子可以在重置时执行任何所需的连接活动。另请参阅
重置操作
PoolEvents.reset() -
-
events– 一个 2 元组列表,每个元组的形式为(callable, target),将在构造时传递给listen()。提供此处是为了在应用方言级别的监听器之前,可以通过create_engine()分配事件监听器。 -
dialect– 一个将负责在 DBAPI 连接上调用 rollback()、close()或 commit()的Dialect。如果省略,则使用内置的“存根”方言。使用create_engine()的应用程序不应使用此参数,因为它由引擎创建策略处理。 -
pre_ping–如果为 True,池将在检出连接时发出“ping”(通常为“SELECT 1”,但是与方言有关)来测试连接是否存活。如果没有,连接将被透明地重新连接,并在成功后,此时间戳之前建立的所有其他池化连接将无效。需要传递方言以解释断开连接错误。
从 1.2 版本开始新增。
method connect() → PoolProxiedConnection
从池中返回一个 DBAPI 连接。
连接被仪器化,这样当调用其close()方法时,连接将会返回到池中。
method dispose() → None
处置此池。
这种方法会使得已经检出的连接保持打开状态,因为它只影响处于池中空闲的连接。
另请参阅
Pool.recreate()
method recreate() → Pool
返回一个新的与此相同类的Pool,并配置相同的创建参数。
此方法与dispose()结合使用,以关闭整个Pool并在其位置创建一个新的。
class sqlalchemy.pool.QueuePool
对打开连接数量施加限制的Pool。
QueuePool 是除了带有:memory:数据库的 SQLite 外,所有Engine对象的默认池化实现。
QueuePool 类不兼容于 asyncio 和create_async_engine()。当使用create_async_engine()时,如果没有指定其他类型的池,将自动使用AsyncAdaptedQueuePool类。
另请参阅
AsyncAdaptedQueuePool
成员
init(), dispose(), recreate()
类签名
类 sqlalchemy.pool.QueuePool (sqlalchemy.pool.base.Pool)
method __init__(creator: _CreatorFnType | _CreatorWRecFnType, pool_size: int = 5, max_overflow: int = 10, timeout: float = 30.0, use_lifo: bool = False, **kw: Any)
构建一个 QueuePool。
参数:
-
creator– 一个可调用函数,返回一个与Pool.creator相同的 DB-API 连接对象。 -
pool_size– 要维护的池的大小,默认为 5。这是池中将持续保留的连接数的最大值。注意,池开始时没有连接;一旦请求了这么多连接,这么多连接就会保留下来。pool_size可以设置为 0 表示没有大小限制;要禁用池,请使用NullPool。 -
max_overflow– 池的最大溢出大小。当检出的连接数量达到池大小设置的大小时,将返回额外的连接,直到达到此限制为止。当这些额外的连接返回到池时,它们将被断开并丢弃。因此,池允许的同时连接总数为 pool_size + max_overflow,池允许的“休眠”连接总数为 pool_size。max_overflow 可以设置为 -1 表示没有溢出限制;并发连接的总数不受限制。默认为 10。 -
timeout– 在放弃返回连接之前等待的秒数。默认为 30.0。这可以是一个浮点数,但受 Python 时间函数的限制,可能不可靠达到十毫秒的级别。 -
use_lifo–使用 LIFO(后进先出)而不是 FIFO(先进先出)来检索连接。使用 LIFO,服务器端的超时方案可以减少在非高峰使用期间使用的连接数。在计划服务器端超时时,请确保使用了重新循环或预先 ping 策略以优雅地处理过时的连接。
版本 1.3 中的新功能。
另请参见
使用 FIFO vs. LIFO
处理断开连接
-
**kw– 其他关键字参数,包括Pool.recycle、Pool.echo、Pool.reset_on_return和其他参数,都将传递给Pool构造函数。
method dispose() → None
处置此池。
此方法使得可能存在检出的连接保持打开状态,因为它只影响池中空闲的连接。
亦参见
Pool.recreate()
method recreate() → QueuePool
返回一个新的Pool,与当前的池具有相同的类,并配置了相同的创建参数。
此方法与 dispose() 结合使用,关闭整个 Pool 并在其位置创建一个新的。
class sqlalchemy.pool.AsyncAdaptedQueuePool
QueuePool 的 asyncio 兼容版本。
当从 create_async_engine() 生成的 AsyncEngine 引擎时,默认使用此池。它使用不使用 threading.Lock 的 asyncio 兼容队列实现。
AsyncAdaptedQueuePool 的参数和操作与 QueuePool 相同。
类签名
类 sqlalchemy.pool.AsyncAdaptedQueuePool (sqlalchemy.pool.impl.QueuePool)
class sqlalchemy.pool.SingletonThreadPool
每个线程维护一个连接的池。
每个线程维护一个连接,从不将连接移动到创建它的线程之外的线程中。
警告
SingletonThreadPool 将在存在超过 pool_size 设置的任意连接时调用 .close(),例如,如果使用的唯一 线程标识 多于 pool_size 指定的数量。此清理是非确定性的,并且不受连接是否正在使用与线程标识相关联的影响。
在未来的版本中,SingletonThreadPool 可能会改进,但在目前的状态下,通常仅用于使用 SQLite :memory: 数据库的测试场景,并不建议用于生产环境。
SingletonThreadPool 类不兼容 asyncio 和 create_async_engine()。
选项与 Pool 相同,还包括:
参数:
pool_size – 一次性维护连接的线程数。默认为五。
当使用基于内存的数据库时,SQLite 方言会自动使用 SingletonThreadPool。参见 SQLite。
成员
connect(), dispose(), recreate()
类签名
类 sqlalchemy.pool.SingletonThreadPool (sqlalchemy.pool.base.Pool)
method connect() → PoolProxiedConnection
从池中返回一个 DBAPI 连接。
连接被仪器化,以便在调用其 close() 方法时,连接将返回到池中。
method dispose() → None
处理此池。
method recreate() → SingletonThreadPool
返回一个新的 Pool,与此相同类的并配置有相同的创建参数。
该方法与 dispose() 结合使用,关闭整个 Pool 并在其位置创建一个新的。
class sqlalchemy.pool.AssertionPool
允许在任何给定时间最多只有一个已签出连接的 Pool。
如果同时签出了多个连接,则会引发异常。 用于调试使用比预期更多的连接的代码。
AssertionPool 类 与 asyncio 兼容,create_async_engine()。
成员
dispose(), recreate()
类签名
类 sqlalchemy.pool.AssertionPool (sqlalchemy.pool.base.Pool)
method dispose() → None
处理此池。
此方法使得可能保持已签出连接处于打开状态,因为它仅影响池中处于空闲状态的连接。
另请参阅
Pool.recreate()
method recreate() → AssertionPool
返回一个新的 Pool,与此相同类的并配置有相同的创建参数。
该方法与 dispose() 结合使用,关闭整个 Pool 并在其位置创建一个新的。
class sqlalchemy.pool.NullPool
不池化连接的 Pool。
相反,它会为每个连接的打开/关闭字面上打开并关闭底层的 DB-API 连接。
此 Pool 实现不支持与重新连接相关的函数,如 recycle 和连接失效,因为没有持续保留连接。
NullPool类与 asyncio 和create_async_engine()兼容。
成员
dispose(), recreate()
类签名
类sqlalchemy.pool.NullPool(sqlalchemy.pool.base.Pool)
method dispose() → None
处置此池。
此方法使得可能存在检出的连接仍然保持打开状态,因为它只影响池中处于空闲状态的连接。
另请参阅
Pool.recreate()
method recreate() → NullPool
返回一个新的Pool,与此相同类别的,并配置有相同的创建参数。
此方法与dispose()一起使用,以关闭整个Pool并创建一个新的。
class sqlalchemy.pool.StaticPool
一种仅包含一个连接的池,用于所有请求。
重新连接相关的函数,如recycle和连接失效(也用于支持自动重新连接),目前只支持部分,并且可能不会产生良好的结果。
StaticPool类与 asyncio 和create_async_engine()兼容。
成员
dispose(), recreate()
类签名
类sqlalchemy.pool.StaticPool(sqlalchemy.pool.base.Pool)
method dispose() → None
处置此池。
此方法使得可能存在检出的连接仍然保持打开状态,因为它只影响池中处于空闲状态的连接。
另请参阅
Pool.recreate()
method recreate() → StaticPool
返回一个新的Pool,与此相同类别的,并配置有相同的创建参数。
此方法与dispose()一起使用,以关闭整个Pool并创建一个新的。
class sqlalchemy.pool.ManagesConnection
两个连接管理接口PoolProxiedConnection和ConnectionPoolEntry的通用基类。
这两个对象通常通过连接池事件钩子在公共 API 中公开,文档位于PoolEvents。
成员
dbapi_connection, driver_connection, info, invalidate(), record_info
版本 2.0 中新增。
attribute dbapi_connection: DBAPIConnection | None
被跟踪的实际 DBAPI 连接的引用。
这是一个符合PEP 249的对象,对于传统的同步式方言,由正在使用的第三方 DBAPI 实现提供。对于 asyncio 方言,实现通常是由 SQLAlchemy 方言本身提供的适配器对象;底层 asyncio 对象可通过ManagesConnection.driver_connection属性获得。
SQLAlchemy 对 DBAPI 连接的接口基于DBAPIConnection协议对象。
另请参阅
ManagesConnection.driver_connection
在使用 Engine 时如何获取原始的 DBAPI 连接?
attribute driver_connection: Any | None
“驱动级别”连接对象由 Python DBAPI 或数据库驱动程序使用。
对于传统的PEP 249 DBAPI 实现,此对象将与ManagesConnection.dbapi_connection的对象相同。对于 asyncio 数据库驱动程序,这将是该驱动程序使用的最终“连接”对象,例如不具有标准 pep-249 方法的asyncpg.Connection对象。
版本 1.4.24 中新增。
另请参阅
ManagesConnection.dbapi_connection
在使用 Engine 时如何获取原始的 DBAPI 连接?
attribute info
与此ManagesConnection实例引用的底层 DBAPI 连接相关联的信息字典,允许将用户定义的数据与连接关联。
此字典中的数据在 DBAPI 连接本身的生命周期内是持久的,包括池中的检入和检出。当连接无效并被新连接替换时,此字典将被清除。
对于未与ConnectionPoolEntry关联的PoolProxiedConnection实例,例如如果它被分离,该属性返回一个仅限于该ConnectionPoolEntry的字典。因此,ManagesConnection.info属性将始终提供一个 Python 字典。
另请参见
ManagesConnection.record_info
method invalidate(e: BaseException | None = None, soft: bool = False) → None
将托管连接标记为失效。
参数:
-
e– 表示连接失效原因的异常对象。 -
soft– 如果为 True,则连接不会关闭;相反,此连接将在下次检出时被回收。
另请参见
更多关于失效的信息
attribute record_info
与此ManagesConnection关联的持久信息字典。
与ManagesConnection.info字典不同,此字典的生命周期与拥有它的ConnectionPoolEntry相同;因此,此字典将在重新连接和特定连接池条目的连接失效时持续存在。
对于未与ConnectionPoolEntry关联的PoolProxiedConnection实例,例如如果它被分离,该属性返回 None。与永远不为 None 的ManagesConnection.info字典形成对比。
另请参见
ManagesConnection.info
class sqlalchemy.pool.ConnectionPoolEntry
代表Pool实例维护单个数据库连接的对象的接口。
ConnectionPoolEntry 对象表示池中特定连接的长期维护,包括使该连接过期或失效以被替换为新连接,而这个新连接将继续由相同的 ConnectionPoolEntry 实例维护。与 PoolProxiedConnection 相比,后者是短期的,每次检出的连接管理器,这个对象的生命周期为连接池中的特定“槽”。
ConnectionPoolEntry 对象在被传递到连接池事件钩子(例如 PoolEvents.connect() 和 PoolEvents.checkout())时,主要对外公开。
新版本 2.0 中:ConnectionPoolEntry 为 _ConnectionRecord 内部类提供了公共界面。
成员
close(), dbapi_connection, driver_connection, in_use, info, invalidate(), record_info
类签名
class sqlalchemy.pool.ConnectionPoolEntry (sqlalchemy.pool.base.ManagesConnection)
method close() → None
关闭由此连接池条目管理的 DBAPI 连接。
attribute dbapi_connection: DBAPIConnection | None
跟踪的实际 DBAPI 连接的引用。
这是一个符合PEP 249标准的对象,对于传统的同步式方言,由正在使用的第三方 DBAPI 实现提供。对于 asyncio 方言,该实现通常是由 SQLAlchemy 方言本身提供的适配器对象;底层 asyncio 对象可通过 ManagesConnection.driver_connection 属性访问。
SQLAlchemy 对 DBAPI 连接的接口基于 DBAPIConnection 协议对象
另请参阅
ManagesConnection.driver_connection
当使用 Engine 时,我如何访问原始的 DBAPI 连接?
attribute driver_connection: Any | None
Python DBAPI 或数据库驱动程序使用的“驱动程序级别”连接对象。
对于传统的PEP 249 DBAPI 实现,这个对象将与ManagesConnection.dbapi_connection的对象相同。对于 asyncio 数据库驱动程序,这将是该驱动程序使用的最终的“连接”对象,例如asyncpg.Connection对象,该对象不具有标准的 pep-249 方法。
从版本 1.4.24 开始新增。
另请参阅
ManagesConnection.dbapi_connection
当使用 Engine 时,我如何访问原始的 DBAPI 连接?
attribute in_use
如果当前检出了连接,则返回 True。
attribute info
继承自 ManagesConnection 的 ManagesConnection.info 属性。
与由此 ManagesConnection 实例引用的底层 DBAPI 连接关联的信息字典,允许将用户定义的数据与连接关联起来。
此字典中的数据在 DBAPI 连接本身的生命周期内是持久的,包括池中的签入和签出。当连接被使无效并替换为新连接时,此字典将被清除。
对于未与ConnectionPoolEntry关联的PoolProxiedConnection实例,例如,如果它被分离,该属性将返回一个仅属于该ConnectionPoolEntry的字典。因此,ManagesConnection.info 属性将始终提供一个 Python 字典。
另请参阅
ManagesConnection.record_info
method invalidate(e: BaseException | None = None, soft: bool = False) → None
继承自 ManagesConnection 的 ManagesConnection.invalidate() 方法。
将管理的连接标记为无效。
参数:
-
e– 表示使无效的原因的异常对象。 -
soft– 如果为 True,则连接不会关闭;相反,此连接将在下次检出时被回收。
另请参阅
关于使无效
attribute record_info
继承自 ManagesConnection 的 ManagesConnection.record_info 属性
与此ManagesConnection关联的持久信息字典。
与ManagesConnection.info字典不同,此字典的生命周期与拥有它的ConnectionPoolEntry的生命周期相同;因此,对于连接池中特定条目的重新连接和连接失效,此字典将持续存在。
对于与ConnectionPoolEntry不相关的PoolProxiedConnection实例,例如如果它被分离,该属性返回 None。与永不为 None 的ManagesConnection.info字典形成对比。
另请参阅
ManagesConnection.info
class sqlalchemy.pool.PoolProxiedConnection
一个类似连接适配器,用于PEP 249 DBAPI 连接,其中包括特定于Pool实现的附加方法。
PoolProxiedConnection是内部_ConnectionFairy实现对象的公共接口;熟悉_ConnectionFairy的用户可以将此对象视为等效。
版本 2.0 中新增:PoolProxiedConnection为_ConnectionFairy内部类提供了公共接口。
成员
close(), dbapi_connection, detach(), driver_connection, info, invalidate(), is_detached, is_valid, record_info
类签名
类sqlalchemy.pool.PoolProxiedConnection(sqlalchemy.pool.base.ManagesConnection)
method close() → None
释放此连接回连接池。
PoolProxiedConnection.close()方法遮蔽了PEP 249的.close()方法,改变其行为以将代理连接释放回连接池。
释放到池中后,连接是否保持“打开”并在 Python 进程中保留,还是实际关闭并从 Python 进程中移除,取决于正在使用的池实现及其配置和当前状态。
attribute dbapi_connection: DBAPIConnection | None
正在跟踪的实际 DBAPI 连接的引用。
这是一个符合PEP 249的对象,对于传统的同步式方言,由正在使用的第三方 DBAPI 实现提供。对于异步方言,实现通常是由 SQLAlchemy 方言本身提供的适配器对象;底层的异步对象可通过ManagesConnection.driver_connection属性获得。
SQLAlchemy 对 DBAPI 连接的接口基于DBAPIConnection协议对象
另请参阅
ManagesConnection.driver_connection
在使用引擎时如何访问原始的 DBAPI 连接?
method detach() → None
将此连接与其池分离。
这意味着当关闭时,连接将不再返回到池中,而是被实际关闭。相关的ConnectionPoolEntry与此 DBAPI 连接解除关联。
请注意,在分离后,池实现施加的任何整体连接限制约束可能会被违反,因为分离的连接已从池的知识和控制中移除。
attribute driver_connection: Any | None
Python DBAPI 或数据库驱动程序使用的“驱动级”连接对象。
对于传统的PEP 249 DBAPI 实现,此对象将与ManagesConnection.dbapi_connection的对象相同。对于异步数据库驱动程序,这将是该驱动程序使用的最终“连接”对象,例如asyncpg.Connection对象,该对象不具有标准的 pep-249 方法。
版本 1.4.24 中的新功能。
另请参阅
ManagesConnection.dbapi_connection
在使用引擎时如何获取原始 DBAPI 连接?
attribute info
继承自 ManagesConnection 的 ManagesConnection.info 属性。
与此ManagesConnection实例引用的底层 DBAPI 连接相关联的信息字典,允许将用户定义的数据与连接相关联。
此字典中的数据对于 DBAPI 连接本身的生命周期是持久的,包括池的签入和签出。当连接被使无效并替换为新连接时,此字典将被清除。
对于与ConnectionPoolEntry不关联的PoolProxiedConnection实例,例如如果它被分离,则该属性返回一个与该ConnectionPoolEntry局部相关的字典。因此,ManagesConnection.info属性始终提供 Python 字典。
另请参阅
ManagesConnection.record_info
method invalidate(e: BaseException | None = None, soft: bool = False) → None
继承自 ManagesConnection 的 ManagesConnection.invalidate() 方法。
将受管理的连接标记为无效。
参数:
-
e– 指示无效原因的异常对象。 -
soft– 如果为 True,则不会关闭连接;相反,此连接将在下次检出时被回收。
另请参阅
更多关于失效的信息
attribute is_detached
如果此PoolProxiedConnection从其池中分离,则返回 True。
attribute is_valid
如果此PoolProxiedConnection仍然引用活动的 DBAPI 连接,则返回 True。
attribute record_info
继承自 ManagesConnection 的 ManagesConnection.record_info 属性。
与此ManagesConnection相关联的持久信息字典。
与ManagesConnection.info字典不同,此字典的生命周期与拥有它的ConnectionPoolEntry相同;因此,对于连接池中特定条目的重新连接和连接失效,此字典将持久存在。
对于不与ConnectionPoolEntry相关联的PoolProxiedConnection实例(例如如果它已分离),该属性返回 None。与永不为 None 的ManagesConnection.info字典形成对比。
另请参阅
ManagesConnection.info
class sqlalchemy.pool._ConnectionFairy
代理一个 DBAPI 连接并提供解引用支持。
此为Pool实现内部使用的对象,为由该Pool提供的 DBAPI 连接提供上下文管理。该类的公共接口由PoolProxiedConnection类描述。请参阅该类获取公共 API 详细信息。
名称“fairy”灵感来源于_ConnectionFairy对象的生命周期是短暂的,因为它仅在从池中检出特定 DBAPI 连接的长度内存在,并且作为透明代理,它大部分时间是不可见的。
另请参阅
PoolProxiedConnection
ConnectionPoolEntry
类签名
类 sqlalchemy.pool._ConnectionFairy (sqlalchemy.pool.base.PoolProxiedConnection)
class sqlalchemy.pool._ConnectionRecord
维护连接池中引用的一个连接的位置。
此为Pool实现内部使用的对象,为由该Pool维护的 DBAPI 连接提供上下文管理。该类的公共接口由ConnectionPoolEntry类描述。请参阅该类获取公共 API 详细信息。
另请参阅
ConnectionPoolEntry
PoolProxiedConnection
类签名
类 sqlalchemy.pool._ConnectionRecord (sqlalchemy.pool.base.ConnectionPoolEntry)
连接池配置
大多数情况下,create_engine() 函数返回的 Engine 已经集成了一个预先配置合理的 QueuePool。如果你只是阅读本节来学习如何启用连接池 - 恭喜!你已经完成了。
最常见的 QueuePool 调优参数可以直接作为关键字参数传递给 create_engine():pool_size、max_overflow、pool_recycle 和 pool_timeout。例如:
engine = create_engine(
"postgresql+psycopg2://me@localhost/mydb", pool_size=20, max_overflow=0
)
所有 SQLAlchemy 连接池实现都有一个共同点,即它们都不会“预先创建”连接 - 所有实现都会在首次使用之前等待创建连接。在那时,如果没有额外的并发检出请求要求更多的连接,就不会创建额外的连接。这就是为什么 create_engine() 默认使用一个大小为五的 QueuePool 是完全可以的,而不用考虑应用程序是否真的需要排队五个连接 - 只有在应用程序实际上同时使用了五个连接时,池才会增长到这个大小,此时使用一个小池是完全适当的默认行为。
注意
QueuePool 类 不兼容 asyncio。当使用 create_async_engine 创建一个 AsyncEngine 实例时,会使用 AsyncAdaptedQueuePool 类,该类使用了一个兼容 asyncio 的队列实现。
切换连接池实现
使用不同类型的池与create_engine()的通常方法是使用poolclass参数。该参数接受从sqlalchemy.pool模块导入的类,并为您处理构建池的详细信息。一个常见的用例是禁用连接池,这可以通过使用NullPool实现来实现:
from sqlalchemy.pool import NullPool
engine = create_engine(
"postgresql+psycopg2://scott:tiger@localhost/test", poolclass=NullPool
)
使用自定义连接函数
参见自定义 DBAPI connect()参数/连接时例程部分,了解各种连接自定义例程的情况。
构造池
要单独使用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")
透明代理的目的是拦截close()调用,以便将 DBAPI 连接返回到池中:
# "close" the connection. Returns
# it to the pool.
conn.close()
当代理被垃圾回收时,它也会将其包含的 DBAPI 连接返回到池中,尽管在 Python 中并不确定这是否立即发生(尽管在 cPython 中是典型的)。然而,不建议这样使用,特别是不支持使用 asyncio DBAPI 驱动程序。
返回时重置
池包含“返回时重置”行为,当连接返回到池中时,将调用 DBAPI 连接的rollback()方法。这样做是为了从连接中移除任何现有的事务状态,这不仅包括未提交的数据,还包括表和行锁。对于大多数 DBAPI,调用rollback()是廉价的,如果 DBAPI 已经完成了一个事务,那么该方法应该是一个空操作。
对于非事务连接禁用返回时重置
对于非常特定的情况,其中 rollback() 不实用,例如当使用配置为 自动提交 或者使用没有 ACID 能力的数据库(如 MySQL 的 MyISAM 引擎)的连接时,可以禁用返回时重置行为,这通常是出于性能考虑。可以通过使用 Pool 的 Pool.reset_on_return 参数来影响,该参数也可以从 create_engine() 中使用 create_engine.pool_reset_on_return 进行设置,传递一个值为 None。下面的示例中进行了说明,结合了 AUTOCOMMIT 的 create_engine.isolation_level 参数设置:
non_acid_engine = create_engine(
"mysql://scott:tiger@host/db",
pool_reset_on_return=None,
isolation_level="AUTOCOMMIT",
)
上述引擎在连接返回到池中时实际上不会执行回滚操作;由于启用了 AUTOCOMMIT,驱动程序也不会执行任何 BEGIN 操作。
自定义的返回重置方案
仅由单个 rollback() 组成的“返回重置”对于某些用例可能不够;特别是,使用临时表的应用程序可能希望这些表在连接签入时自动删除。一些(但并非全部)后端包含可以在数据库连接范围内“重置”这些表的功能,这可能是连接池重置的一种理想行为。其他服务器资源,例如准备好的语句句柄和服务器端语句缓存,可能会在签入过程之后持续存在,具体取决于具体情况是否希望如此。同样,一些(但再次并非全部)后端可能提供了重置此状态的方法。已知具有此类重置方案的两个 SQLAlchemy 包含的方言包括 Microsoft SQL Server,其中通常使用一个名为 sp_reset_connection 的未记录但广为人知的存储过程,以及 PostgreSQL,它有一系列命令包括 DISCARD RESET、DEALLOCATE 和 UNLISTEN。
以下示例说明了如何使用PoolEvents.reset()事件钩子,在返回时用 Microsoft SQL Server 的sp_reset_connection存储过程替换重置。create_engine.pool_reset_on_return参数设置为None,以便完全替换默认行为。自定义钩子实现在任何情况下都调用.rollback(),因为通常重要的是 DBAPI 自己的提交/回滚跟踪与事务状态保持一致:
from sqlalchemy import create_engine
from sqlalchemy import event
mssql_engine = create_engine(
"mssql+pyodbc://scott:tiger⁵HHH@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()
在版本 2.0.0b3 中更改:为PoolEvents.reset()事件添加了额外的状态参数,并另外确保事件对所有“重置”事件都被调用,因此它适用于自定义“重置”处理程序的地方。之前使用PoolEvents.checkin()处理程序的方案仍然可用。
另请参阅
-
连接池临时表/资源重置 - 在 Microsoft SQL Server 文档中
-
连接池临时表/资源重置 - 在 PostgreSQL 文档中
记录返回时的重置事件
对包括返回时的重置在内的池事件进行记录可以设置为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
对非事务连接禁用返回时的重置
对于一些特定情况下rollback()不适用的情况,比如在使用配置为自动提交或者在使用没有 ACID 功能的数据库,比如 MySQL 的 MyISAM 引擎时,可以禁用返回时的重置行为,通常出于性能原因。可以通过使用Pool.reset_on_return参数来实现,该参数也可以从create_engine()中获取,作为create_engine.pool_reset_on_return,传递一个值为None。下面的示例中演示了这一点,结合了AUTOCOMMIT的create_engine.isolation_level参数设置:
non_acid_engine = create_engine(
"mysql://scott:tiger@host/db",
pool_reset_on_return=None,
isolation_level="AUTOCOMMIT",
)
由于启用了 AUTOCOMMIT,上述引擎在连接返回到池时实际上不会执行 ROLLBACK 操作;由于驱动程序也不会执行任何 BEGIN 操作。
自定义返回时重置方案
对于一些使用临时表的应用程序,仅由一个rollback()组成的“返回时重置”可能不足够;特别是,使用临时表的应用程序可能希望在连接检入时自动删除这些表。一些(但并非所有)后端包括可以在数据库连接范围内“重置”这些表的功能,这可能是连接池重置的一种理想行为。其他服务器资源,如准备好的语句句柄和服务器端语句缓存,可能会在检入过程之后持续存在,具体取决于具体情况是否希望这样。同样,一些(但再次不是所有)后端可能提供一种重置此状态的方法。已知具有此类重置方案的两个 SQLAlchemy 包含的方言包括 Microsoft SQL Server,其中通常使用一个名为sp_reset_connection的未记录但广为人知的存储过程,以及 PostgreSQL,后者有一系列良好记录的命令,包括DISCARD RESET,DEALLOCATE和UNLISTEN。
以下示例说明了如何使用 PoolEvents.reset() 事件钩子将返回时的重置替换为 Microsoft SQL Server 的 sp_reset_connection 存储过程。 create_engine.pool_reset_on_return 参数设置为 None,以便自定义方案完全替换默认行为。自定义钩子实现在任何情况下都调用 .rollback(),因为通常重要的是 DBAPI 自己的提交/回滚跟踪与事务的状态保持一致:
from sqlalchemy import create_engine
from sqlalchemy import event
mssql_engine = create_engine(
"mssql+pyodbc://scott:tiger⁵HHH@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()
从版本 2.0.0b3 中更改:为 PoolEvents.reset() 事件添加了额外的状态参数,并确保该事件被调用以进行所有“重置”发生,因此它适用于自定义“重置”处理程序的位置。以前使用 PoolEvents.checkin() 处理程序的方案仍然可用。
请参阅
-
临时表 / 资源重置以进行连接池 - 在 Microsoft SQL Server 文档中
-
临时表 / 资源重置以进行连接池 - 在 PostgreSQL 文档中
记录返回时的重置事件
可以将池事件的日志设置为 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
池事件
连接池支持事件接口,允许在第一次连接时、每次新连接时以及连接的签入和签出时执行钩子。有关详细信息,请参阅 PoolEvents。
处理断开连接
连接池具有刷新单个连接以及其整个连接集的能力,将先前池化的连接设置为“无效”。一个常见的用例是当数据库服务器重新启动时,连接池能够优雅地恢复,并且所有先前建立的连接都不再可用。有两种方法可以实现这一点。
断开连接处理 - 悲观
悲观方法是指在每次连接池检出时在 SQL 连接上发出测试语句,以测试数据库连接是否仍然可用。该实现是方言特定的,并且利用了 DBAPI 特定的 ping 方法,或者使用简单的 SQL 语句如“SELECT 1”,以便测试连接的活性。
此方法在连接检出过程中增加了一点开销,但否则是完全消除由于过期的池化连接而导致的数据库错误的最简单可靠方法。调用应用程序无需担心组织操作以便能够从池中检出的过期连接中恢复。
通过使用 Pool.pre_ping 参数,可以在每次连接池检出时对连接进行悲观测试,此参数可从 create_engine() 中通过 create_engine.pool_pre_ping 参数获得:
engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)
“预连接测试”功能在每种方言上都是基于每个数据库适配器(DBAPI)特定的“ping”方法运行,如果不可用,则会发出与“SELECT 1”等效的 SQL,并捕获任何错误,并将错误检测为“断开”情况。如果 ping / 错误检查确定连接不可用,则连接将立即被回收,并且所有其他比当前时间更早的池化连接都将被作废,以便在下次检出它们时,它们也将在使用之前被回收。
如果数据库在“预连接测试”运行时仍然不可用,则初始连接将失败,并且将正常传播连接失败的错误。在数据库可用于连接但无法响应“ping”的情况下,“pre_ping”将尝试最多三次,然后放弃,并传播最后收到的数据库错误。
需要注意的是,预先 ping 的方法不适用于在事务或其他 SQL 操作中断开连接的情况。如果数据库在事务进行中变得不可用,则事务将丢失并引发数据库错误。虽然Connection对象将检测“断开”情况并在此条件发生时重新使用连接并使其余连接池无效,但引发异常的个别操作将丢失,应用程序需要放弃该操作或重新尝试整个事务。如果引擎使用 DBAPI 级别的自动提交连接进行配置,如设置包括 DBAPI 自动提交的事务隔离级别,则连接可能会在操作中透明地重新连接使用事件。有关示例,请参阅如何自动“重试”语句执行?部分。
对于使用“SELECT 1”并捕获错误以检测断开连接的方言,可以使用DialectEvents.handle_error()钩子来增强新的特定于后端的错误消息的断开连接测试。
自定义 / 传统悲观 Ping
在添加create_engine.pool_pre_ping之前,历史上一直通过ConnectionEvents.engine_connect()引擎事件手动执行“预先 ping”方法。以下是最常见的配方,供参考,以防应用程序已经使用此类配方,或者需要特殊行为:
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
上述配方的优点在于我们利用了 SQLAlchemy 用于检测那些已知指示“断开”情况的 DBAPI 异常以及Engine对象在此条件发生时正确使当前连接池无效并允许当前Connection重新验证到新的 DBAPI 连接的能力。
断开连接处理 - 乐观
当不使用悲观处理时,以及当数据库在事务中的连接期间关闭和/或重新启动时,处理陈旧/关闭连接的另一种方法是让 SQLAlchemy 在发生断开连接时处理,此时池中的所有连接都将被作废,意味着它们被认为是陈旧的,并将在下次检出时刷新。此行为假定Pool与Engine一起使用。Engine具有可以检测断开连接事件并自动刷新池的逻辑。
当Connection尝试使用 DBAPI 连接,并引发与“断开”事件对应的异常时,连接将被作废。然后,Connection调用Pool.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"))
上面的示例说明了在检测到断开连接事件后,刷新池不需要任何特殊干预,池在此后会正常运行。然而,在数据库不可用事件发生时,每个正在使用的连接会引发一个数据库异常。在使用 ORM 会话的典型 Web 应用程序中,上述情况将对应于一个请求失败并显示 500 错误,然后 Web 应用程序在此之后会正常继续。因此,这种方法是“乐观”的,不预期频繁的数据库重启。
设置池回收
可以增强“乐观”方法的另一个设置是设置池回收参数。该参数防止池使用已经过一定年龄的特定连接,并适用于数据库后端,例如 MySQL,在特定时间后自动关闭陈旧连接:
from sqlalchemy import create_engine
e = create_engine("mysql+mysqldb://scott:tiger@localhost/test", pool_recycle=3600)
在上述情况下,任何已经打开超过一小时的 DBAPI 连接将在下次检出时被作废并替换。请注意,作废仅发生在检出时 - 而不是在任何处于已检出状态的连接上。pool_recycle是Pool本身的一个函数,与是否使用Engine无关。### 更多关于作废的信息
Pool提供了“连接失效”服务,允许对连接进行显式失效以及在确定使连接无法使用的条件下自动失效。
“失效”意味着特定的 DBAPI 连接被从池中移除并丢弃。如果不清楚连接本身是否可能已关闭,则会调用此连接的.close()方法,但是如果此方法失败,则会记录异常,但操作仍将继续。
当使用Engine时,Connection.invalidate()方法是显式失效的常规入口点。导致 DBAPI 连接失效的其他条件包括:
-
当调用诸如
connection.execute()之类的方法时引发的 DBAPI 异常,例如OperationalError被检测为指示所谓的“断开”条件。由于 Python DBAPI 没有用于确定异常性质的标准系统,所有 SQLAlchemy 方言都包含一个称为is_disconnect()的系统,它将检查异常对象的内容,包括字符串消息以及其中包含的任何潜在错误代码,以确定此异常是否指示连接不再可用。如果是这种情况,则调用_ConnectionFairy.invalidate()方法,然后丢弃 DBAPI 连接。 -
当连接被返回到池中,并且调用
connection.rollback()或connection.commit()方法时,根据池的“返回时重置”行为,抛出异常。最后尝试调用连接的.close()方法,然后将其丢弃。 -
当实现
PoolEvents.checkout()的监听器引发DisconnectionError异常时,表示连接将无法使用,需要进行新的连接尝试。
所有发生的失效都将调用PoolEvents.invalidate()事件。### 支持断开场景的新数据库错误代码
每个 SQLAlchemy 方言都包括一个名为 is_disconnect() 的例程,每当遇到 DBAPI 异常时就会调用它。DBAPI 异常对象被传递给此方法,方言特定的启发式将确定接收到的错误代码是否指示数据库连接已“断开”,或者处于无法使用的状态,这表明应该对其进行回收。这里应用的启发式可以通过 DialectEvents.handle_error() 事件钩子进行自定义,该钩子通常通过拥有的 Engine 对象进行建立。使用此钩子,所有发生的错误都将传递一个称为 ExceptionContext 的上下文对象。自定义事件钩子可以控制特定错误是否应被视为“断开”情况,以及此断开是否应导致整个连接池无效化。
例如,要添加支持将 Oracle 错误代码 DPY-1001 和 DPY-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 中新增)。
参见
DialectEvents.handle_error() ### 断开连接处理 - 悲观
悲观的方法是指在每次连接池检出时发出一个测试语句,以测试数据库连接是否仍然可用。该实现是方言特定的,可以使用特定于 DBAPI 的 ping 方法,也可以使用简单的 SQL 语句如“SELECT 1”来测试连接的活动性。
这种方法会给连接检出过程增加一点开销,但是除此之外,它是完全消除由于过时的连接池连接而导致数据库错误的最简单和可靠的方法。调用应用程序不需要关心组织操作以便从连接池中检出过时的连接。
通过使用 create_engine() 的 create_engine.pool_pre_ping 参数,可以通过使用 Pool.pre_ping 参数来实现在检出时对连接进行悲观测试:
engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)
“预连接”功能是在每个方言基础上运行的,通过调用特定于 DBAPI 的“ping”方法,或者如果不可用,则会发出等效于“SELECT 1”的 SQL,捕获任何错误并将错误检测为“断开”情况。如果 ping / 错误检查确定连接不可用,则连接将立即被回收,并且所有比当前时间更旧的池化连接都将被作废,以便下次检出时,在使用之前也将被回收。
如果在“预 ping”运行时数据库仍然不可用,则初始连接将失败,并且连接失败的错误将正常传播。在数据库可用于连接但无法响应“ping”的情况下,将尝试最多三次“预 ping”,然后放弃,传播上次收到的数据库错误。
需要注意的是,预连接方法不适用于事务中断开的连接或其他 SQL 操作。如果数据库在事务进行中变得不可用,则事务将丢失并引发数据库错误。虽然 Connection 对象会检测到“断开”情况并在发生此情况时回收连接以及使其余连接池无效,但引发异常的个别操作将丢失,由应用程序来放弃操作或重新尝试整个事务。如果引擎使用 DBAPI 级别的自动提交连接进行配置,如 设置事务隔离级别,包括 DBAPI 自动提交,则可以使用事件在操作中透明地重新连接。有关示例,请参阅 如何“自动重试”语句执行? 节。
对于使用“SELECT 1”并捕获错误以检测断开的方言,可以使用 DialectEvents.handle_error() 钩子来增加新的后端特定错误消息的断开测试。
自定义 / 传统悲观的预连接
在添加 create_engine.pool_pre_ping 之前,历史上“预 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
上述配方的优点是我们利用 SQLAlchemy 的设施来检测那些已知指示“断开连接”情况的 DBAPI 异常,以及 Engine 对象在此条件发生时正确地使当前连接池无效并允许当前 Connection 重新验证到新的 DBAPI 连接。 #### 自定义/遗留悲观 ping
在添加 create_engine.pool_pre_ping 之前,"预先 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
上述配方的优点是我们利用 SQLAlchemy 的设施来检测那些已知指示“断开连接”情况的 DBAPI 异常,以及 Engine 对象在此条件发生时正确地使当前连接池无效并允许当前 Connection 重新验证到新的 DBAPI 连接。
断开处理 - 乐观
当不使用悲观处理,并且在事务中连接使用期间数据库关闭和/或重新启动时,处理陈旧/关闭连接的另一种方法是让 SQLAlchemy 在断开连接时处理,此时池中的所有连接都将被作废,意味着它们被假定为陈旧的,并将在下次检出时刷新。此行为假定与 Pool 一起使用 Engine。Engine 具有可以检测到断开连接事件并自动刷新池的逻辑。
当 Connection 尝试使用 DBAPI 连接,并引发与“断开”事件对应的异常时,连接将被作废。然后,Connection 调用 Pool.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"))
上面的示例说明,在检测到断开连接事件后,不需要任何特殊干预来刷新池,池在此后会正常运行。然而,在数据库不可用事件发生时,每个正在使用的连接都会引发一个数据库异常。在使用 ORM 会话的典型 Web 应用程序中,上述情况将对应于一个请求失败并返回 500 错误,然后 Web 应用程序在此之后会正常继续运行。因此,这种方法是“乐观的”,不预期频繁地重启数据库。
设置池回收
可以增强“乐观”方法的另一个设置是设置池回收参数。该参数防止池使用已经存在一段时间的特定连接,适用于数据库后端(如 MySQL),该后端在一段特定时间后会自动关闭已经过时的连接:
from sqlalchemy import create_engine
e = create_engine("mysql+mysqldb://scott:tiger@localhost/test", pool_recycle=3600)
在上述设置中,任何已经打开超过一小时的 DBAPI 连接将在下一次检出时被作废并替换。请注意,作废仅在检出时发生 - 不会作用于任何处于已检出状态的连接。pool_recycle 是 Pool 本身的一个函数,与是否使用 Engine 无关。 #### 设置池回收
可以增强“乐观”方法的另一个设置是设置池回收参数。该参数防止池使用已经存在一段时间的特定连接,适用于数据库后端(如 MySQL),该后端在一段特定时间后会自动关闭已经过时的连接:
from sqlalchemy import create_engine
e = create_engine("mysql+mysqldb://scott:tiger@localhost/test", pool_recycle=3600)
在上述设置中,任何已经打开超过一小时的 DBAPI 连接将在下一次检出时被作废并替换。请注意,作废仅在检出时发生 - 不会作用于任何处于已检出状态的连接。pool_recycle 是 Pool 本身的一个函数,与是否使用 Engine 无关。
更多关于作废的内容
Pool提供“连接失效”服务,允许显式失效连接以及在确定使连接不可用的条件下自动失效。
“失效”意味着特定的 DBAPI 连接从池中移除并丢弃。如果不清楚连接本身是否关闭,则在此连接上调用.close()方法,但如果此方法失败,则记录异常但操作仍继续。
在使用Engine时,Connection.invalidate()方法通常是显式失效的入口点。其他可能使 DBAPI 连接失效的条件包括:
-
例如
OperationalError这样的 DBAPI 异常,在调用connection.execute()等方法时引发,被检测为所谓的“断开”条件。由于 Python DBAPI 没有确定异常性质的标准系统,所有 SQLAlchemy 方言都包括一个名为is_disconnect()的系统,它将检查异常对象的内容,包括字符串消息和其中包含的任何潜在错误代码,以确定此异常是否指示连接不再可用。如果是这种情况,将调用_ConnectionFairy.invalidate()方法,然后丢弃 DBAPI 连接。 -
当连接返回到池中,并调用
connection.rollback()或connection.commit()方法时,根据池的“返回时重置”行为,抛出异常。将最后尝试在连接上调用.close()方法,然后将其丢弃。 -
当实现
PoolEvents.checkout()的监听器引发DisconnectionError异常时,表示连接将无法使用,需要进行新的连接尝试。
所有发生的失效将调用PoolEvents.invalidate()事件。
支持断开情景的新数据库错误代码
SQLAlchemy 方言(dialects)中都包含一个名为 is_disconnect() 的程序,当遇到 DBAPI 异常时会调用该程序。DBAPI 异常对象会传递给这个方法,在这里,方言特定的启发法则将确定接收到的错误代码是否指示数据库连接已被“断开”,或者处于其他无法使用的状态,表明应该重新使用该连接。此处应用的启发式方法可以使用 DialectEvents.handle_error() 事件钩子进行自定义,通常是通过所属的 Engine 对象建立的。使用此钩子,所有发生的错误都会传递一个称为 ExceptionContext 的上下文对象。自定义事件钩子可以控制特定错误是否应该被视为“断开”情况,以及此断开是否应该导致整个连接池无效化。
例如,要添加支持将 Oracle 错误代码 DPY-1001 和 DPY-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 版本中新增)。
另见
DialectEvents.handle_error()
使用 FIFO vs. LIFO
QueuePool 类特征一个名为 QueuePool.use_lifo 的标志,也可以通过标志 create_engine.pool_use_lifo 在 create_engine() 中访问。将此标志设置为 True 会导致池的“队列”行为变为“堆栈”,例如,返回到池中的最后一个连接将在下一次请求中首先被使用。与池的先入先出长期行为相反,后者产生一个轮转效果,依次使用池中的每个连接,LIFO 模式允许多余的连接在池中保持空闲,从而允许服务器端超时方案关闭这些连接。FIFO 和 LIFO 的区别基本上是池是否在空闲期间保持一组完整的连接准备就绪:
engine = create_engine("postgreql://", pool_use_lifo=True, pool_pre_ping=True)
此外,我们还使用了create_engine.pool_pre_ping标志,以便由服务器端关闭的连接被连接池优雅地处理,并替换为新连接。
注意,此标志仅适用于QueuePool的使用。
版本 1.3 中的新功能。
另请参阅
处理断开连接
使用连接池与多进程或 os.fork()
在使用连接池时(通过create_engine()创建的Engine),至关重要的是,不要共享池化的连接给分叉的进程。 TCP 连接表示为文件描述符,通常跨进程边界工作,这意味着这将导致在两个或更多完全独立的 Python 解释器状态的代表性之间并发访问文件描述符。
根据驱动程序和操作系统的具体情况,此处出现的问题范围从不起作用的连接到被多个进程同时使用的套接字连接,导致消息中断(后者通常是最常见的情况)。
SQLAlchemy Engine对象指的是现有数据库连接的连接池。因此,当此对象被复制到子进程时,目标是确保不会携带任何数据库连接。有四种一般方法来解决这个问题:
-
使用
NullPool禁用连接池。这是最简单的、一次性的系统,防止Engine重复使用任何连接:from sqlalchemy.pool import NullPool engine = create_engine("mysql+mysqldb://user:pass@host/dbname", poolclass=NullPool) -
在子进程的初始化阶段调用
Engine.dispose(),传递值为False的Engine.dispose.close参数。这样新进程就不会触及任何父进程的连接,而是会以新的连接开始。这是推荐的方法: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)版本 1.4.33 中的新功能:添加了
Engine.dispose.close参数,以允许在子进程中替换连接池,而不会干扰父进程使用的连接。 -
在创建子进程之前直接调用
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() -
可以向连接池应用事件处理程序,以测试跨进程边界共享的连接,并使其无效:
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) )在上面,我们使用了类似于断开处理 - 悲观中描述的方法来处理在不同父进程中起源的 DBAPI 连接,将其视为“无效”连接,强制池回收连接记录以建立新连接。
上述策略将适用于在进程之间共享Engine的情况。仅仅上述步骤并不足以处理在进程边界共享特定Connection的情况;最好将特定Connection的范围局限于单个进程(和线程)。直接跨进程共享任何类型的进行中的事务状态,比如已开始事务并引用活动Connection实例的 ORM Session对象,也不受支持;最好在新进程中创建新的Session对象。
直接使用池实例
可以直接使用池实现而不需要引擎。这可用于只希望使用池行为而不需要所有其他 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 文档 - 可用的池实现
| 对象名称 | 描述 |
|---|---|
| _ConnectionFairy | 代理一个 DBAPI 连接,并提供返回引用支持。 |
| _ConnectionRecord | 维护连接池中的位置,引用一个池化连接。 |
| AssertionPool | 允许每次最多只有一个已签出连接的Pool。 |
| 异步适配队列池 | 队列池的一个适用于 asyncio 的版本。 |
| 连接池条目 | 代表池实例的个别数据库连接的对象的接口。 |
| 管理连接 | 用于两个连接管理接口池代理连接和连接池条目的通用基类。 |
| 空池 | 不对连接进行池化的池。 |
| 池 | 连接池的抽象基类。 |
| 池代理连接 | 用于PEP 249 DBAPI 连接的类似连接的适配器,其中包括特定于池实现的附加方法。 |
| 队列池 | 对打开连接数量施加限制的池。 |
| 单例线程池 | 每个线程维护一个连接的池。 |
| 静态池 | 用于所有请求的恰好一个连接的池。 |
class sqlalchemy.pool.Pool
连接池的抽象基类。
成员
init(), connect(), dispose(), recreate()
类签名
类sqlalchemy.pool.Pool (sqlalchemy.log.Identified, sqlalchemy.event.registry.EventTarget)的签名
method __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)
构建一个池。
参数:
-
creator– 一个可调用的函数,返回一个 DB-API 连接对象。该函数将带有参数调用。 -
recycle– 如果设置为除-1 以外的值,则连接回收之间的秒数,这意味着在检出时,如果超过此超时,则连接将被关闭并替换为新打开的连接。默认为-1。 -
logging_name– 用于“sqlalchemy.pool”记录器中生成的日志记录的“name”字段的字符串标识符。默认为对象 id 的十六进制字符串。 -
echo–如果为真,则连接池将记录信息输出,例如当连接失效时以及当连接被回收时,默认日志处理程序为
sys.stdout。如果设置为字符串"debug",日志将包括池检出和检入。Pool.echo参数也可以通过使用create_engine.echo_pool参数从create_engine()调用中设置。另请参阅
配置日志记录 - 如何配置日志记录的更多详细信息。
-
reset_on_return–确定在将连接返回到池中时执行的步骤,这些步骤否则不会由
Connection处理。可以通过create_engine()通过create_engine.pool_reset_on_return参数来使用。Pool.reset_on_return可以有以下任何值:-
"rollback"- 在连接上调用 rollback(),释放锁和事务资源。这是默认值。绝大多数情况下应该保持此值不变。 -
"commit"- 在连接上调用 commit(),释放锁和事务资源。在某些情况下,如微软 SQL Server,如果发出了 commit,则可能需要提交。然而,这个值比 ‘rollback’ 更危险,因为任何存在于事务中的数据更改都会无条件地提交。 -
None- 在连接上不执行任何操作。如果数据库/DBAPI 在所有时刻都以纯“自动提交”模式工作,或者使用PoolEvents.reset()事件处理程序建立了自定义重置处理程序,则此设置可能是合适的。 -
True- 与 ‘rollback’ 相同,这是为了向后兼容而存在的。 -
False- 与 None 相同,这是为了向后兼容而存在的。
为了进一步定制返回时的重置,可以使用
PoolEvents.reset()事件钩子,该钩子可以在重置时执行任何所需的连接活动。另请参阅
返回时重置
PoolEvents.reset() -
-
events– 一个 2-元组列表,每个元组的形式为(callable, target),将在构造时传递给listen()。此处提供是为了在应用方言级别的监听器之前,可以通过create_engine()分配事件监听器。 -
dialect– 一个处理 DBAPI 连接的回滚(rollback())、关闭(close())或提交(commit())工作的Dialect。如果省略,将使用内置的“存根”方言。使用create_engine()的应用程序不应使用此参数,因为它由引擎创建策略处理。 -
pre_ping–如果为 True,则池将在检出连接时发出“ping”(通常为“SELECT 1”,但是是特定于方言的),以测试连接是否活动。如果不活动,则连接将被透明地重新连接,并在成功后,所有在该时间戳之前建立的其他池连接将无效。还需要传递一个方言以解释断开连接错误。
1.2 版本中新增。
method connect() → PoolProxiedConnection
从池中返回一个 DBAPI 连接。
连接被检测工具检测,以便在调用其 close() 方法时,连接将被返回到池中。
method dispose() → None
处置此池。
此方法可能导致仍处于检出状态的连接保持打开状态,因为它仅影响池中处于空闲状态的连接。
另请参见
Pool.recreate()
method recreate() → Pool
返回一个新的 Pool,与此相同类的池,并配置相同的创建参数。
此方法与 dispose() 结合使用,用于关闭整个 Pool 并在其位置创建一个新的 Pool。
class sqlalchemy.pool.QueuePool
施加对打开连接数量的限制的 Pool。
QueuePool 是除了 SQLite 的 :memory: 数据库之外,所有 Engine 对象的默认池实现。
QueuePool 类与 asyncio 不兼容,并且 create_async_engine()。当使用 create_async_engine() 时,如果没有指定其他类型的池,则会自动使用 AsyncAdaptedQueuePool 类。
另请参见
AsyncAdaptedQueuePool
成员
init(), dispose(), recreate()
类签名
类sqlalchemy.pool.QueuePool(sqlalchemy.pool.base.Pool)
method __init__(creator: _CreatorFnType | _CreatorWRecFnType, pool_size: int = 5, max_overflow: int = 10, timeout: float = 30.0, use_lifo: bool = False, **kw: Any)
构造一个 QueuePool。
参数:
-
creator– 一个可调用函数,返回一个与Pool.creator相同的 DB-API 连接对象。 -
pool_size– 要维护的池的大小,默认为 5。这是将持续保留在池中的最大连接数。请注意,池开始时没有连接;一旦请求了这个数量的连接,这个数量的连接将保持不变。pool_size可设置为 0,表示没有大小限制;要禁用池化,请使用NullPool。 -
max_overflow– 池的最大溢出大小。当已签出连接的数量达到 pool_size 中设置的大小时,将返回额外的连接,直到达到此限制为止。当这些额外的连接返回到池中时,它们将被断开并丢弃。因此,池允许的同时连接数是 pool_size + max_overflow,池允许的“睡眠”连接总数是 pool_size。max_overflow 可设置为-1,表示无溢出限制;不会对并发连接的总数设置限制。默认为 10。 -
timeout– 在放弃返回连接之前等待的秒数。默认为 30.0。这可以是一个浮点数,但受 Python 时间函数的限制,可能不可靠,精度在几十毫秒内。 -
use_lifo–在检索连接时使用 LIFO(后进先出)而不是 FIFO(先进先出)。使用 LIFO,服务器端的超时方案可以在非高峰使用期间减少使用的连接数量。在规划服务器端超时时,请确保使用回收或预检查策略来优雅地处理陈旧的连接。
新功能,版本 1.3。
另请参阅
使用 FIFO vs. LIFO
处理断开连接
-
**kw– 其他关键字参数,包括Pool.recycle、Pool.echo、Pool.reset_on_return等,将传递给Pool构造函数。
method dispose() → None
释放此池。
此方法可能导致已签出的连接保持打开状态,因为它只影响池中处于空闲状态的连接。
另请参阅
Pool.recreate()
method recreate() → QueuePool
返回一个新的Pool,与此对象相同类别的对象,并配置相同的创建参数。
此方法与 dispose() 结合使用,以关闭整个 Pool 并在其位置创建一个新的池。
class sqlalchemy.pool.AsyncAdaptedQueuePool
QueuePool 的一个与 asyncio 兼容的版本。
当使用从 create_async_engine() 生成的 AsyncEngine 引擎时,默认使用此池。它使用了一个与 asyncio 兼容的队列实现,不使用 threading.Lock。
AsyncAdaptedQueuePool 的参数和操作与 QueuePool 相同。
类签名
class sqlalchemy.pool.AsyncAdaptedQueuePool (sqlalchemy.pool.impl.QueuePool)
class sqlalchemy.pool.SingletonThreadPool
每个线程维护一个连接的池。
每个线程维护一个连接,永远不会将连接移动到其创建的线程之外。
警告
SingletonThreadPool 将对超出 pool_size 大小设置的任意连接调用 .close(),例如,如果使用的唯一 线程标识 大于 pool_size 所指定的数量。此清理是非确定性的,并且不会因连接是否与这些线程标识关联并当前正在使用而受到影响。
SingletonThreadPool 在未来的版本中可能会得到改进,但在当前状态下,它通常仅用于使用 SQLite 的 :memory: 数据库的测试场景,并不建议用于生产环境。
SingletonThreadPool 类 不兼容 asyncio 和 create_async_engine()。
选项与 Pool 相同,以及:
参数:
pool_size – 同时维护连接的线程数。默认为五。
当使用基于内存的数据库时,SQLite 方言会自动使用 SingletonThreadPool。请参阅 SQLite。
成员
connect(), dispose(), recreate()
类签名
类sqlalchemy.pool.SingletonThreadPool(sqlalchemy.pool.base.Pool)
method connect() → PoolProxiedConnection
从池中返回一个 DBAPI 连接。
连接被仪器化,这样当调用其close()方法时,连接将被返回到池中。
method dispose() → None
释放此池。
method recreate() → SingletonThreadPool
返回一个新的Pool,与此相同类别,并使用相同的创建参数配置。
此方法与dispose()结合使用,关闭整个Pool并创建一个新的替代品。
class sqlalchemy.pool.AssertionPool
一个允许在任何给定时间最多有一个已检出连接的Pool。
如果同时检出了多个连接,则会引发异常。 对于调试使用比期望的连接更多的代码很有用。
AssertionPool类与 asyncio 和create_async_engine() 兼容。
成员
dispose(), recreate()
类签名
类sqlalchemy.pool.AssertionPool(sqlalchemy.pool.base.Pool)
method dispose() → None
释放此池。
此方法使得已检出连接保持打开的可能性,因为它仅影响池中处于空闲状态的连接。
另请参阅
Pool.recreate()
method recreate() → AssertionPool
返回一个新的Pool,与此相同类别,并使用相同的创建参数配置。
此方法与dispose()结合使用,关闭整个Pool并创建一个新的替代品。
class sqlalchemy.pool.NullPool
不池化连接的池。
反而,它会逐个连接地打开和关闭底层的 DB-API 连接。
此池实现不支持与重新连接相关的函数,如recycle和连接失效,因为没有连接持续存在。
NullPool类与asyncio 和create_async_engine()兼容。
成员
dispose(), recreate()
类签名
类sqlalchemy.pool.NullPool(sqlalchemy.pool.base.Pool)
method dispose() → None
处置此池。
这种方法留下了已检出连接保持打开的可能性,因为它只影响池中处于空闲状态的连接。
另见
Pool.recreate()
method recreate() → NullPool
返回一个新的Pool,与此相同的类,并配置相同的创建参数。
此方法与dispose()一起使用,以关闭整个Pool并在其位置创建一个新的。
class sqlalchemy.pool.StaticPool
一个连接池,用于所有请求。
重新连接相关的函数,如recycle和连接失效(也用于支持自动重新连接),目前仅部分支持,可能不会产生良好的结果。
StaticPool类与asyncio 和create_async_engine()兼容。
成员
dispose(), recreate()
类签名
类sqlalchemy.pool.StaticPool(sqlalchemy.pool.base.Pool)
method dispose() → None
处置此池。
这种方法留下了已检出连接保持打开的可能性,因为它只影响池中处于空闲状态的连接。
另见
Pool.recreate()
method recreate() → StaticPool
返回一个新的Pool,与此相同的类,并配置相同的创建参数。
此方法与dispose()一起使用,以关闭整个Pool并在其位置创建一个新的。
class sqlalchemy.pool.ManagesConnection
两个连接管理接口的共同基类PoolProxiedConnection和ConnectionPoolEntry。
这两个对象通常通过连接池事件钩子在公共 API 中公开,详见 PoolEvents。
成员
dbapi_connection, driver_connection, info, invalidate(), record_info
新版本 2.0 中新增。
attribute dbapi_connection: DBAPIConnection | None
跟踪的实际 DBAPI 连接的引用。
这是一个PEP 249-兼容对象,对于传统的同步式方言,由使用的第三方 DBAPI 实现提供。对于 asyncio 方言,实现通常是 SQLAlchemy 方言本身提供的适配器对象;底层 asyncio 对象可通过 ManagesConnection.driver_connection 属性获得。
SQLAlchemy 对 DBAPI 连接的接口基于 DBAPIConnection 协议对象
另请参阅
ManagesConnection.driver_connection
在使用引擎时如何获取原始 DBAPI 连接?
attribute driver_connection: Any | None
Python DBAPI 或数据库驱动程序中使用的“驱动程序级别”连接对象。
对于传统的PEP 249 DBAPI 实现,此对象将与 ManagesConnection.dbapi_connection 的对象相同。对于 asyncio 数据库驱动程序,这将是该驱动程序使用的最终“连接”对象,例如 asyncpg.Connection 对象,该对象不会具有标准的 pep-249 方法。
新版本 1.4.24 中新增。
另请参阅
ManagesConnection.dbapi_connection
在使用引擎时如何获取原始 DBAPI 连接?
attribute info
与此 ManagesConnection 实例引用的底层 DBAPI 连接相关联的信息字典,允许将用户定义的数据与连接关联起来。
此字典中的数据在 DBAPI 连接本身的生命周期内是持久的,包括池检入和检出期间。当连接无效并替换为新连接时,此字典将被清除。
对于一个未关联ConnectionPoolEntry的PoolProxiedConnection实例,例如如果它被分离,该属性返回一个仅限于该ConnectionPoolEntry的字典。因此,ManagesConnection.info属性将始终提供一个 Python 字典。
另请参阅
ManagesConnection.record_info
method invalidate(e: BaseException | None = None, soft: bool = False) → None
将受管连接标记为无效。
参数:
-
e– 指示失效原因的异常对象。 -
soft– 如果为 True,则连接不会关闭;相反,此连接将在下次检出时被回收。
另请参阅
更多关于失效化的信息
attribute record_info
与此ManagesConnection关联的持久信息字典。
与ManagesConnection.info字典不同,此字典的生命周期与拥有它的ConnectionPoolEntry相同;因此,此字典将在重新连接和特定连接池条目的失效化过程中持续存在。
对于一个未关联ConnectionPoolEntry的PoolProxiedConnection实例,例如如果它被分离,该属性返回 None。与永不为 None 的ManagesConnection.info字典形成对比。
另请参阅
ManagesConnection.info
class sqlalchemy.pool.ConnectionPoolEntry
代表在Pool实例上维护单个数据库连接的对象的接口。
ConnectionPoolEntry 对象表示池中特定连接的长期维护,包括使该连接过期或无效以将其替换为新连接,这将继续由同一ConnectionPoolEntry 实例维护。与PoolProxiedConnection 相比,后者是短期的,每次检出的连接管理器,该对象的寿命为连接池中特定“槽位”的寿命。
当交付给连接池事件钩子时,ConnectionPoolEntry 对象主要对公共 API 代码可见,例如PoolEvents.connect() 和 PoolEvents.checkout()。
2.0 版新功能:ConnectionPoolEntry 为_ConnectionRecord 内部类提供了公共界面。
成员
close(), dbapi_connection, driver_connection, in_use, info, invalidate(), record_info
类签名
类sqlalchemy.pool.ConnectionPoolEntry (sqlalchemy.pool.base.ManagesConnection)
method close() → None
关闭此连接池条目管理的 DBAPI 连接。
attribute dbapi_connection: DBAPIConnection | None
对正在跟踪的实际 DBAPI 连接的引用。
这是一个PEP 249-兼容对象,对于传统的同步样式方言,由使用的第三方 DBAPI 实现提供。对于 asyncio 方言,实现通常是 SQLAlchemy 方言本身提供的适配器对象;基础 asyncio 对象可通过ManagesConnection.driver_connection 属性获得。
SQLAlchemy 对 DBAPI 连接的接口基于DBAPIConnection 协议对象
另请参阅
ManagesConnection.driver_connection
当使用引擎时,如何获取原始的 DBAPI 连接?
attribute driver_connection: Any | None
由 Python DBAPI 或数据库驱动程序使用的“驱动程序级”连接对象。
对于传统的PEP 249 DBAPI 实现,该对象将与 ManagesConnection.dbapi_connection 相同。对于异步数据库驱动程序,这将是该驱动程序使用的最终“连接”对象,例如 asyncpg.Connection 对象,该对象不具有标准的 pep-249 方法。
新版本 1.4.24 中的新增内容。
另请参阅
ManagesConnection.dbapi_connection
当使用引擎时,如何获取原始的 DBAPI 连接?
attribute in_use
如果连接当前正在被检出,则返回 True
attribute info
继承自 ManagesConnection.info 属性
与此 ManagesConnection 实例引用的底层 DBAPI 连接关联的信息字典,允许将用户定义的数据与连接关联起来。
此字典中的数据对于 DBAPI 连接本身的生命周期是持久的,包括池中的检入和检出。当连接被失效并替换为新连接时,该字典将被清除。
对于不与 ConnectionPoolEntry 关联的 PoolProxiedConnection 实例,例如如果它被分离了,该属性将返回一个局部于该 ConnectionPoolEntry 的字典。因此,ManagesConnection.info 属性将始终提供一个 Python 字典。
另请参阅
ManagesConnection.record_info
method invalidate(e: BaseException | None = None, soft: bool = False) → None
继承自 ManagesConnection.invalidate() 方法
将受管理的连接标记为失效。
参数:
-
e– 表示失效原因的异常对象。 -
soft– 如果为 True,则不会关闭连接;相反,该连接将在下次检出时被回收。
另请参阅
更多关于失效化的内容
attribute record_info
继承自 ManagesConnection 的 ManagesConnection.record_info 属性
与此ManagesConnection关联的持久信息字典。
与ManagesConnection.info字典不同,此字典的生命周期与拥有它的ConnectionPoolEntry相同;因此,对于连接池中特定条目的重新连接和连接失效,此字典将持续存在。
对于未与ConnectionPoolEntry关联的PoolProxiedConnection实例,例如如果它被分离,该属性返回 None。与永不为 None 的ManagesConnection.info字典形成对比。
另请参阅
ManagesConnection.info
class sqlalchemy.pool.PoolProxiedConnection
用于PEP 249 DBAPI 连接的类似连接适配器,包括特定于Pool实现的附加方法。
PoolProxiedConnection是内部_ConnectionFairy实现对象的公共接口;熟悉_ConnectionFairy的用户可以将此对象视为等效。
新版本 2.0 中:PoolProxiedConnection提供了_ConnectionFairy内部类的公共接口。
成员
close(), dbapi_connection, detach(), driver_connection, info, invalidate(), is_detached, is_valid, record_info
类签名
类sqlalchemy.pool.PoolProxiedConnection (sqlalchemy.pool.base.ManagesConnection)
method close() → None
将此连接释放回到池中。
PoolProxiedConnection.close() 方法覆盖了PEP 249的.close()方法,改变了其行为,使其释放代理连接返回到连接池。
将连接释放到池中后,连接在 Python 进程中是否保持“打开”并保留在池中,还是实际关闭并从 Python 进程中删除,取决于正在使用的池实现及其配置和当前状态。
attribute dbapi_connection: DBAPIConnection | None
对被跟踪的实际 DBAPI 连接的引用。
这是一个PEP 249兼容对象,对于传统的同步风格方言,由使用的第三方 DBAPI 实现提供。对于 asyncio 方言,实现通常是 SQLAlchemy 方言本身提供的适配器对象;底层的 asyncio 对象可通过ManagesConnection.driver_connection属性访问。
SQLAlchemy 的 DBAPI 连接接口基于DBAPIConnection协议对象
另请参阅
ManagesConnection.driver_connection
在使用 Engine 时,如何获取原始的 DBAPI 连接?
method detach() → None
将此连接与其连接池分离。
这意味着当关闭连接时,连接将不再返回到池中,而是被实际关闭。关联的ConnectionPoolEntry与此 DBAPI 连接解除关联。
请注意,在分离后,由池实现强加的任何整体连接限制约束可能会被违反,因为分离的连接从池的知识和控制中移除。
attribute driver_connection: Any | None
Python DBAPI 或数据库驱动程序使用的“驱动程序级别”的连接对象。
对于传统的PEP 249 DBAPI 实现,该对象将与ManagesConnection.dbapi_connection的对象相同。对于一个 asyncio 数据库驱动程序,这将是该驱动程序使用的最终的“连接”对象,例如asyncpg.Connection对象,它不会具有标准的 pep-249 方法。
版本 1.4.24 中的新功能。
另请参阅
ManagesConnection.dbapi_connection
在使用 Engine 时如何获取原始的 DBAPI 连接?
attribute info
继承自 ManagesConnection 的 ManagesConnection.info 属性
与此ManagesConnection实例引用的底层 DBAPI 连接相关联的信息字典,允许将用户定义的数据与连接关联起来。
这个字典中的数据在整个 DBAPI 连接的生命周期内是持久的,包括连接池的签入和签出。当连接失效并被新连接替换时,该字典将被清除。
对于不与ConnectionPoolEntry关联的PoolProxiedConnection实例,例如如果它被分离,该属性返回一个仅限于该ConnectionPoolEntry的字典。因此,ManagesConnection.info属性将始终提供一个 Python 字典。
另请参阅
ManagesConnection.record_info
method invalidate(e: BaseException | None = None, soft: bool = False) → None
继承自 ManagesConnection 的 ManagesConnection.invalidate() 方法
将托管连接标记为失效。
参数:
-
e– 一个表示失效原因的异常对象。 -
soft– 如果为 True,则连接不会关闭;相反,此连接将在下次签出时被回收。
另请参阅
更多关于失效的信息
attribute is_detached
如果此PoolProxiedConnection已从其池中分离,则返回 True。
attribute is_valid
如果此PoolProxiedConnection仍指向活动的 DBAPI 连接,则返回 True。
attribute record_info
继承自 ManagesConnection 的 ManagesConnection.record_info 属性
与此ManagesConnection相关联的持久信息字典。
与ManagesConnection.info字典不同,此字典的生命周期是由拥有它的ConnectionPoolEntry决定的;因此,这个字典将在连接池中的特定条目的重新连接和连接失效时保持不变。
对于未关联到ConnectionPoolEntry的PoolProxiedConnection实例,例如如果它是分离的,则该属性返回 None。与永远不会为 None 的ManagesConnection.info字典相比。
另请参阅
ManagesConnection.info
class sqlalchemy.pool._ConnectionFairy
代理 DBAPI 连接并提供解引用支持。
这是Pool实现内部使用的对象,用于为该Pool提供上下文管理,以由该Pool提供的 DBAPI 连接。该类的公共接口由PoolProxiedConnection类描述。请参阅该类以获取公共 API 详细信息。
名称“fairy”灵感来自于_ConnectionFairy对象的生命周期是短暂的,因为它仅在从池中检出的特定 DBAPI 连接的长度内存在,并且作为透明代理,它大部分时间是不可见的。
另请参阅
PoolProxiedConnection
ConnectionPoolEntry
类签名
类 sqlalchemy.pool._ConnectionFairy (sqlalchemy.pool.base.PoolProxiedConnection)
class sqlalchemy.pool._ConnectionRecord
维护连接池中引用池化连接的位置。
这是Pool实现内部使用的对象,用于为该Pool维护的 DBAPI 连接提供上下文管理。该类的公共接口由ConnectionPoolEntry类描述。请参阅该类以获取公共 API 详细信息。
另请参阅
ConnectionPoolEntry
PoolProxiedConnection
类签名
类 sqlalchemy.pool._ConnectionRecord(sqlalchemy.pool.base.ConnectionPoolEntry)
核心事件
本节描述了 SQLAlchemy Core 中提供的事件接口。有关事件监听 API 的介绍,请参阅 Events。ORM 事件在 ORM Events 中描述。
| 对象名称 | 描述 |
|---|---|
| Events | 为特定目标类型定义事件监听函数。 |
class sqlalchemy.event.base.Events
为特定目标类型定义事件监听函数。
成员
dispatch
类签名
类sqlalchemy.event.Events (sqlalchemy.event._HasEventsDispatch)
attribute dispatch: _Dispatch[_ET] = <sqlalchemy.event.base.EventsDispatch object>
参考 _Dispatch class。
对抗 _Dispatch._events
连接池事件
| 对象名称 | 描述 |
|---|---|
| PoolEvents | Pool的可用事件。 |
| PoolResetState | 描述传递给PoolEvents.reset()连接池事件的 DBAPI 连接的状态。 |
class sqlalchemy.events.PoolEvents
Pool的可用事件。
这里的方法定义了事件的名称以及传递给监听器函数的成员的名称。
例如:
from sqlalchemy import event
def my_on_checkout(dbapi_conn, connection_rec, connection_proxy):
"handle an on checkout event"
event.listen(Pool, 'checkout', my_on_checkout)
除了接受Pool类和Pool实例外,PoolEvents还接受Engine对象和Engine类作为目标,这将被解析为给定引擎的.pool属性或Pool类:
engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test")
# will associate with engine.pool
event.listen(engine, 'checkout', my_on_checkout)
成员
checkin(), checkout(), close(), close_detached(), connect(), detach(), dispatch, first_connect(), invalidate(), reset(), soft_invalidate()
类签名
类sqlalchemy.events.PoolEvents (sqlalchemy.event.Events)
method checkin(dbapi_connection: DBAPIConnection | None, connection_record: ConnectionPoolEntry) → None
当连接返回到池时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'checkin')
def receive_checkin(dbapi_connection, connection_record):
"listen for the 'checkin' event"
# ... (event handling logic) ...
请注意,连接可能已关闭,并且如果连接已失效,则可能为 None。对于分离连接,不会调用checkin(它们不会返回到池中)。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。
method checkout(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry, connection_proxy: PoolProxiedConnection) → None
当从连接池中检索到连接时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'checkout')
def receive_checkout(dbapi_connection, connection_record, connection_proxy):
"listen for the 'checkout' event"
# ... (event handling logic) ...
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。 -
connection_proxy–PoolProxiedConnection对象,将代理 DBAPI 连接的公共接口,直到检出结束。
如果引发DisconnectionError,当前连接将被处理并检索到一个新的连接。所有检出监听器的处理将中止,并使用新连接重新启动。
另请参见
ConnectionEvents.engine_connect() - 一个类似的事件,发生在创建新的Connection时。
method close(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry) → None
当关闭 DBAPI 连接时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'close')
def receive_close(dbapi_connection, connection_record):
"listen for the 'close' event"
# ... (event handling logic) ...
事件在关闭发生之前发出。
连接关闭可能会失败;通常是因为连接已经关闭。如果关闭操作失败,连接将被丢弃。
close()事件对应于仍与池相关联的连接。要拦截分离连接的关闭事件,请使用close_detached()。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。
method close_detached(dbapi_connection: DBAPIConnection) → None
当分离的 DBAPI 连接关闭时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'close_detached')
def receive_close_detached(dbapi_connection):
"listen for the 'close_detached' event"
# ... (event handling logic) ...
在关闭发生之前发出事件。
连接的关闭可能失败;通常是因为连接已关闭。如果关闭操作失败,则连接将被丢弃。
参数:
dbapi_connection – 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection 属性。
method connect(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry) → None
在给定的 Pool 中首次创建特定 DBAPI 连接时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'connect')
def receive_connect(dbapi_connection, connection_record):
"listen for the 'connect' event"
# ... (event handling logic) ...
此事件允许捕获在使用 DBAPI 模块级别的 .connect() 方法产生新的 DBAPI 连接之后的直接点。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。
method detach(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry) → None
当一个 DBAPI 连接从池中“分离”时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'detach')
def receive_detach(dbapi_connection, connection_record):
"listen for the 'detach' event"
# ... (event handling logic) ...
此事件在分离发生后发出。连接不再与给定的连接记录关联。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。
attribute dispatch: _Dispatch[_ET] = <sqlalchemy.event.base.PoolEventsDispatch object>
回到 _Dispatch 类的引用。
双向针对 _Dispatch._events
method first_connect(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry) → None
当第一次从特定的 Pool 中检出 DBAPI 连接时调用一次。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'first_connect')
def receive_first_connect(dbapi_connection, connection_record):
"listen for the 'first_connect' event"
# ... (event handling logic) ...
PoolEvents.first_connect() 的理由是根据所有连接使用的设置确定有关特定系列数据库连接的信息。由于特定的 Pool 引用单个“创建者”函数(在 Engine 中引用 URL 和连接选项使用),通常可以假定关于单个连接的观察结果对所有后续连接都是有效的,例如数据库版本,服务器和客户端编码设置,排序规则设置等等。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。
method invalidate(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry, exception: BaseException | None) → None
在要“失效”DBAPI 连接时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'invalidate')
def receive_invalidate(dbapi_connection, connection_record, exception):
"listen for the 'invalidate' event"
# ... (event handling logic) ...
每当调用ConnectionPoolEntry.invalidate()方法时,无论是通过 API 使用还是通过“自动失效”,都会触发此事件,而且没有soft标志。
事件发生在对连接调用.close()的最终尝试之前。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。 -
exception– 对应于此失效原因的异常对象,如果有的话。可能为None。
另请参阅
更多关于失效的信息
method reset(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry, reset_state: PoolResetState) → None
在池化连接发生“重置”操作之前调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'reset')
def receive_reset(dbapi_connection, connection_record, reset_state):
"listen for the 'reset' event"
# ... (event handling logic) ...
# DEPRECATED calling style (pre-2.0, will be removed in a future release)
@event.listens_for(SomeEngineOrPool, 'reset')
def receive_reset(dbapi_connection, connection_record):
"listen for the 'reset' event"
# ... (event handling logic) ...
在 2.0 版本中更改:PoolEvents.reset()事件现在接受参数PoolEvents.reset.dbapi_connection, PoolEvents.reset.connection_record, PoolEvents.reset.reset_state。支持接受先前参数签名的监听器函数将在将来的版本中删除。
此事件表示在将 DBAPI 连接返回到池中或丢弃之前调用rollback()方法时发生。可以使用此事件钩子实现自定义“重置”策略,也可以结合使用Pool.reset_on_return参数禁用默认的“重置”行为。
PoolEvents.reset() 和 PoolEvents.checkin() 事件的主要区别在于 PoolEvents.reset() 不仅适用于将返回池的池化连接,还适用于使用 Connection.detach() 方法分离的连接以及由于连接在被检入之前发生垃圾回收而被丢弃的 asyncio 连接。
请注意,不会为使用 Connection.invalidate() 使无效的连接调用此事件。这些事件可以通过 PoolEvents.soft_invalidate() 和 PoolEvents.invalidate() 事件钩子拦截,并且所有“连接关闭”事件可以通过 PoolEvents.close() 拦截。
PoolEvents.reset() 事件通常紧跟着 PoolEvents.checkin() 事件,在连接在重置后立即被丢弃的情况下除外。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。 -
reset_state–PoolResetState实例,提供有关正在重置连接的情况的信息。从版本 2.0 开始新增。
另请参见
返回时重置
ConnectionEvents.rollback()
ConnectionEvents.commit()
method soft_invalidate(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry, exception: BaseException | None) → None
当要“软使无效” DBAPI 连接时调用此事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'soft_invalidate')
def receive_soft_invalidate(dbapi_connection, connection_record, exception):
"listen for the 'soft_invalidate' event"
# ... (event handling logic) ...
每当使用 soft 标志调用 ConnectionPoolEntry.invalidate() 方法时,都会调用此事件。
软失效是指跟踪此连接的连接记录将在当前连接签入后强制重新连接。它不会在调用它的点主动关闭 dbapi_connection。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。 -
exception– 无效原因对应的异常对象,如果没有则可能是None。
class sqlalchemy.events.PoolResetState
描述 DBAPI 连接在传递给PoolEvents.reset()连接池事件时的状态。
成员
asyncio_safe, terminate_only, transaction_was_reset
在版本 2.0.0b3 中新增。
attribute asyncio_safe: bool
指示重置操作是否发生在期望在 asyncio 应用程序中存在的封闭事件循环范围内。
如果连接正在被垃圾回收,则为 False。
attribute terminate_only: bool
指示连接是否立即终止并且不被签入到池中。
这发生在失效的连接以及未被调用代码清理地处理的 asyncio 连接,而是被垃圾回收时。在后一种情况下,不能在垃圾回收中安全地运行 asyncio 连接上的操作,因为不一定存在事件循环。
attribute transaction_was_reset: bool
指示 DBAPI 连接上的事务是否已经由Connection对象实质上“重置”。
如果Connection上有事务状态,并且然后没有使用Connection.rollback()或Connection.commit()方法关闭事务;相反,事务在Connection.close()方法内联关闭,因此在到达此事件时保证保持不存在。
SQL 执行和连接事件
| 对象名称 | 描述 |
|---|---|
| ConnectionEvents | Connection和Engine的可用事件。 |
| 方言事件 | 用于执行替换函数的事件接口。 |
class sqlalchemy.events.ConnectionEvents
Connection和Engine的可用事件。
这里的方法定义了事件的名称以及传递给监听器函数的成员的名称。
事件监听器可以与任何Connection或Engine类或实例相关联,例如一个Engine,例如:
from sqlalchemy import event, create_engine
def before_cursor_execute(conn, cursor, statement, parameters, context,
executemany):
log.info("Received statement: %s", statement)
engine = create_engine('postgresql+psycopg2://scott:tiger@localhost/test')
event.listen(engine, "before_cursor_execute", before_cursor_execute)
或者使用特定的Connection:
with engine.begin() as conn:
@event.listens_for(conn, 'before_cursor_execute')
def before_cursor_execute(conn, cursor, statement, parameters,
context, executemany):
log.info("Received statement: %s", statement)
当方法使用语句参数调用时,例如在after_cursor_execute()或before_cursor_execute()中,语句是准备发送到连接的 DBAPI cursor的确切 SQL 字符串Dialect。
before_execute()和before_cursor_execute()事件也可以使用retval=True标志来建立,这允许修改发送到数据库的语句和参数。before_cursor_execute()事件在这里特别有用,可以添加临时字符串转换,例如注释,以适用于所有执行:
from sqlalchemy.engine import Engine
from sqlalchemy import event
@event.listens_for(Engine, "before_cursor_execute", retval=True)
def comment_sql_calls(conn, cursor, statement, parameters,
context, executemany):
statement = statement + " -- some comment"
return statement, parameters
注意
ConnectionEvents 可以建立在任何组合的 Engine、Connection,以及这些类的实例上。对于给定的 Connection 实例,所有四个范围的事件都会触发。但是,出于性能原因,Connection 对象在实例化时确定其父 Engine 是否已经建立了事件侦听器。在依赖的 Connection 实例实例化后,向 Engine 类或 Engine 实例添加的事件侦听器通常不会对该 Connection 实例可用。而是,新添加的侦听器将对在父 Engine 类或实例上建立这些事件侦听器之后创建的 Connection 实例产生影响。
参数:
retval=False – 仅适用于 before_execute() 和 before_cursor_execute() 事件。当为 True 时,用户定义的事件函数必须有一个返回值,即替换给定语句和参数的参数元组。有关特定返回参数的描述,请参见这些方法。
成员
after_cursor_execute(), after_execute(), before_cursor_execute(), before_execute(), begin(), begin_twophase(), commit(), commit_twophase(), dispatch, engine_connect(), engine_disposed(), prepare_twophase(), release_savepoint(), rollback(), rollback_savepoint(), rollback_twophase(), savepoint(), set_connection_execution_options(), set_engine_execution_options()
类签名
类sqlalchemy.events.ConnectionEvents (sqlalchemy.event.Events)
method after_cursor_execute(conn: Connection, cursor: DBAPICursor, statement: str, parameters: _DBAPIAnyExecuteParams, context: ExecutionContext | None, executemany: bool) → None
在执行后拦截低级游标 execute() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'after_cursor_execute')
def receive_after_cursor_execute(conn, cursor, statement, parameters, context, executemany):
"listen for the 'after_cursor_execute' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
cursor– DBAPI 游标对象。如果语句是一个 SELECT,将会有待处理的结果,但不应该消耗这些结果,因为它们会被CursorResult需要。 -
statement– 字符串 SQL 语句,就像传递给 DBAPI 的一样 -
parameters– 字典、元组或传递给 DBAPI 游标的execute()或executemany()方法的参数列表。在某些情况下可能为None。 -
context– 使用的ExecutionContext对象。可能为None。 -
executemany– 布尔值,如果为True,则这是一个executemany()调用,如果为False,则这是一个execute()调用。
method after_execute(conn: Connection, clauseelement: Executable, multiparams: _CoreMultiExecuteParams, params: _CoreSingleExecuteParams, execution_options: _ExecuteOptions, result: Result[Any]) → None
在执行后拦截高级 execute() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'after_execute')
def receive_after_execute(conn, clauseelement, multiparams, params, execution_options, result):
"listen for the 'after_execute' event"
# ... (event handling logic) ...
# DEPRECATED calling style (pre-1.4, will be removed in a future release)
@event.listens_for(SomeEngine, 'after_execute')
def receive_after_execute(conn, clauseelement, multiparams, params, result):
"listen for the 'after_execute' event"
# ... (event handling logic) ...
1.4 版本变更:ConnectionEvents.after_execute() 事件现在接受参数 ConnectionEvents.after_execute.conn, ConnectionEvents.after_execute.clauseelement, ConnectionEvents.after_execute.multiparams, ConnectionEvents.after_execute.params, ConnectionEvents.after_execute.execution_options, ConnectionEvents.after_execute.result。将来版本将删除对接受前述“已弃用”参数签名的监听器函数的支持。
参数:
-
conn–Connection对象 -
clauseelement– SQL 表达式构造,Compiled实例或传递给Connection.execute()的字符串语句。 -
multiparams– 多个参数集,一个字典列表。 -
params– 单个参数集,一个字典。 -
execution_options–传递给语句的执行选项字典,如果有的话。这是将要使用的所有选项的合并,包括语句的选项、连接的选项以及传递给方法本身的用于执行 2.0 风格的选项。
-
result– 执行生成的CursorResult。
method before_cursor_execute(conn: Connection, cursor: DBAPICursor, statement: str, parameters: _DBAPIAnyExecuteParams, context: ExecutionContext | None, executemany: bool) → Tuple[str, _DBAPIAnyExecuteParams] | None
在执行之前拦截低级别游标 execute() 事件,接收要针对游标调用的字符串 SQL 语句和特定于 DBAPI 的参数列表。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, parameters, context, executemany):
"listen for the 'before_cursor_execute' event"
# ... (event handling logic) ...
此事件既可用于记录,也可用于对 SQL 字符串进行后期修改。对于除了特定于目标后端的参数修改之外的参数修改,它不太理想。
可以选择使用 retval=True 标志建立此事件。在这种情况下,应返回 statement 和 parameters 参数作为两个元组:
@event.listens_for(Engine, "before_cursor_execute", retval=True)
def before_cursor_execute(conn, cursor, statement,
parameters, context, executemany):
# do something with statement, parameters
return statement, parameters
参见 ConnectionEvents 中的示例。
参数:
-
conn–Connection对象 -
cursor– DBAPI 游标对象 -
statement– 字符串 SQL 语句,如传递给 DBAPI -
parameters– 字典、元组或传递给 DBAPIcursor的execute()或executemany()方法的参数列表。在某些情况下可能为None。 -
context– 正在使用的ExecutionContext对象。可能为None。 -
executemany– 布尔值,如果为True,则为executemany()调用,如果为False,则为execute()调用。
另请参阅
before_execute()
after_cursor_execute()
method before_execute(conn: Connection, clauseelement: Executable, multiparams: _CoreMultiExecuteParams, params: _CoreSingleExecuteParams, execution_options: _ExecuteOptions) → Tuple[Executable, _CoreMultiExecuteParams, _CoreSingleExecuteParams] | None
拦截高级别的 execute() 事件,在渲染为 SQL 之前接收未编译的 SQL 构造和其他对象。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'before_execute')
def receive_before_execute(conn, clauseelement, multiparams, params, execution_options):
"listen for the 'before_execute' event"
# ... (event handling logic) ...
# DEPRECATED calling style (pre-1.4, will be removed in a future release)
@event.listens_for(SomeEngine, 'before_execute')
def receive_before_execute(conn, clauseelement, multiparams, params):
"listen for the 'before_execute' event"
# ... (event handling logic) ...
在 1.4 版本中更改:ConnectionEvents.before_execute() 事件现在接受参数 ConnectionEvents.before_execute.conn、ConnectionEvents.before_execute.clauseelement、ConnectionEvents.before_execute.multiparams、ConnectionEvents.before_execute.params、ConnectionEvents.before_execute.execution_options 的支持。在未来版本中,将删除接受前述“已弃用”参数签名的侦听器函数的支持。
此事件对于调试 SQL 编译问题以及数据库发送的参数的早期操作非常有用,因为此处的参数列表将以一致的格式呈现。
此事件可以选择使用 retval=True 标志来建立。在这种情况下,应将 clauseelement、multiparams 和 params 参数作为三元组返回:
@event.listens_for(Engine, "before_execute", retval=True)
def before_execute(conn, clauseelement, multiparams, params):
# do something with clauseelement, multiparams, params
return clauseelement, multiparams, params
参数:
-
conn–Connection对象 -
clauseelement– SQL 表达式构造,Compiled实例,或传递给Connection.execute()的字符串语句。 -
multiparams– 多个参数集,字典列表。 -
params– 单个参数集,一个字典。 -
execution_options–执行选项字典,与语句一起传递,如果有的话。这是将要使用的所有选项的合并,包括语句的选项、连接的选项以及传递给方法本身的选项,用于 2.0 风格的执行。
也请参阅
before_cursor_execute()
method begin(conn: Connection) → None
拦截 begin() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'begin')
def receive_begin(conn):
"listen for the 'begin' event"
# ... (event handling logic) ...
参数:
conn – Connection 对象
method begin_twophase(conn: Connection, xid: Any) → None
拦截 begin_twophase() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'begin_twophase')
def receive_begin_twophase(conn, xid):
"listen for the 'begin_twophase' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
xid– 两阶段 XID 标识符
method commit(conn: Connection) → None
拦截由 Transaction 发起的提交事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'commit')
def receive_commit(conn):
"listen for the 'commit' event"
# ... (event handling logic) ...
注意,如果 reset_on_return 标志设置为 'commit',则 Pool 也可能在归还时 “自动提交” DBAPI 连接。要拦截此提交,请使用 PoolEvents.reset() 钩子。
参数:
conn – Connection 对象
method commit_twophase(conn: Connection, xid: Any, is_prepared: bool) → None
拦截 commit_twophase() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'commit_twophase')
def receive_commit_twophase(conn, xid, is_prepared):
"listen for the 'commit_twophase' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
xid– 两阶段 XID 标识符 -
is_prepared– 布尔值,指示是否调用了TwoPhaseTransaction.prepare()。
attribute dispatch: _Dispatch[_ET] = <sqlalchemy.event.base.ConnectionEventsDispatch object>
回溯到 _Dispatch 类。
双向 _Dispatch._events
method engine_connect(conn: Connection) → None
拦截新建 Connection。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'engine_connect')
def receive_engine_connect(conn):
"listen for the 'engine_connect' event"
# ... (event handling logic) ...
# DEPRECATED calling style (pre-2.0, will be removed in a future release)
@event.listens_for(SomeEngine, 'engine_connect')
def receive_engine_connect(conn, branch):
"listen for the 'engine_connect' event"
# ... (event handling logic) ...
从版本 2.0 开始更改:ConnectionEvents.engine_connect() 事件现在接受参数 ConnectionEvents.engine_connect.conn。将来的版本中将删除对接受上述“弃用”之前参数签名的侦听器函数的支持。
通常,此事件是直接调用 Engine.connect() 方法的直接结果。
它与 PoolEvents.connect() 方法不同,后者是指在 DBAPI 级别对数据库的实际连接;DBAPI 连接可能会被池化并重复使用多次。相比之下,此事件仅与在此类 DBAPI 连接周围生成更高级别的 Connection 包装器有关。
它还与 PoolEvents.checkout() 事件不同,后者特定于 Connection 对象,而不是 PoolEvents.checkout() 处理的 DBAPI 连接,尽管该 DBAPI 连接可以通过 Connection.connection 属性在此处获得。但请注意,如果 Connection 无效并重新建立,则单个 Connection 对象的生命周期中实际上可以有多个 PoolEvents.checkout() 事件。
参数:
conn – Connection 对象。
另请参阅
PoolEvents.checkout() 单个 DBAPI 连接的低级别池检出事件
method engine_disposed(engine: Engine) → None
拦截 Engine.dispose() 方法被调用的情况。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'engine_disposed')
def receive_engine_disposed(engine):
"listen for the 'engine_disposed' event"
# ... (event handling logic) ...
Engine.dispose() 方法指示引擎“处理”它的连接池(例如 Pool),并用新的连接池替换它。处理旧连接池的效果是关闭现有的已检入连接。新连接池在首次使用之前不会建立任何新连接。
这个事件可用于指示应该清理与 Engine 相关的资源,但要注意,Engine 仍然可以用于新请求,此时它将重新获取连接资源。
method prepare_twophase(conn: Connection, xid: Any) → None
拦截 prepare_twophase() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'prepare_twophase')
def receive_prepare_twophase(conn, xid):
"listen for the 'prepare_twophase' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
xid– 两阶段 XID 标识符
method release_savepoint(conn: Connection, name: str, context: None) → None
拦截 release_savepoint() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'release_savepoint')
def receive_release_savepoint(conn, name, context):
"listen for the 'release_savepoint' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
name– 用于保存点的指定名称。 -
context– 未使用
method rollback(conn: Connection) → None
拦截由 Transaction 启动的 rollback() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'rollback')
def receive_rollback(conn):
"listen for the 'rollback' event"
# ... (event handling logic) ...
请注意,如果 reset_on_return 标志设置为其默认值 'rollback',Pool 在归还时也会“自动回滚” DBAPI 连接。要拦截此回滚,请使用 PoolEvents.reset() 钩子。
参数:
conn – Connection 对象
另请参阅
PoolEvents.reset()
method rollback_savepoint(conn: Connection, name: str, context: None) → None
拦截 rollback_savepoint() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'rollback_savepoint')
def receive_rollback_savepoint(conn, name, context):
"listen for the 'rollback_savepoint' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
name– 用于保存点的指定名称。 -
context– 未使用
method rollback_twophase(conn: Connection, xid: Any, is_prepared: bool) → None
拦截 rollback_twophase() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'rollback_twophase')
def receive_rollback_twophase(conn, xid, is_prepared):
"listen for the 'rollback_twophase' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
xid– 两阶段 XID 标识符 -
is_prepared– 布尔值,指示是否调用了TwoPhaseTransaction.prepare()。
method savepoint(conn: Connection, name: str) → None
拦截 savepoint() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'savepoint')
def receive_savepoint(conn, name):
"listen for the 'savepoint' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
name– 用于保存点的指定名称。
method set_connection_execution_options(conn: Connection, opts: Dict[str, Any]) → None
拦截 Connection.execution_options() 方法调用时。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'set_connection_execution_options')
def receive_set_connection_execution_options(conn, opts):
"listen for the 'set_connection_execution_options' event"
# ... (event handling logic) ...
此方法在新的 Connection 生成后调用,具有新更新的执行选项集,但在 Dialect 对这些新选项之前。
请注意,当从其父Engine继承执行选项的新Connection被生成时,不会调用此方法;要拦截此条件,请使用ConnectionEvents.engine_connect()事件。
参数:
-
conn– 新复制的Connection对象 -
opts–传递给
Connection.execution_options()方法的选项字典。此字典可以就地修改,以影响最终生效的选项。版本 2.0 中的新内容:
opts字典可以就地修改。
另请参阅
ConnectionEvents.set_engine_execution_options() - 当调用Engine.execution_options()时调用的事件。
method set_engine_execution_options(engine: Engine, opts: Dict[str, Any]) → None
当调用Engine.execution_options()方法时拦截。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'set_engine_execution_options')
def receive_set_engine_execution_options(engine, opts):
"listen for the 'set_engine_execution_options' event"
# ... (event handling logic) ...
Engine.execution_options()方法生成Engine的浅拷贝,其中存储了新的选项。这个新的Engine被传递到这里。此方法的一个特定应用是将ConnectionEvents.engine_connect()事件处理程序添加到给定的Engine上,该处理程序将执行一些针对这些执行选项的特定于每个Connection的任务。
参数:
-
conn– 新复制的Engine对象 -
opts–传递给
Connection.execution_options()方法的选项字典。此字典可以就地修改,以影响最终生效的选项。版本 2.0 中的新内容:
opts字典可以就地修改。
另请参阅
ConnectionEvents.set_connection_execution_options() - 当调用Connection.execution_options()时调用的事件。
class sqlalchemy.events.DialectEvents
用于执行替换函数的事件接口。
这些事件允许直接检测和替换与 DBAPI 交互的关键方言函数。
注意
DialectEvents 钩子应被视为半公开和实验性质的。这些钩子不适用于一般情况,并且仅适用于那些需要将复杂的 DBAPI 机制重新注入到现有方言中的情况。对于一般用途的语句拦截事件,请使用ConnectionEvents 接口。
另请参阅
ConnectionEvents.before_cursor_execute()
ConnectionEvents.before_execute()
ConnectionEvents.after_cursor_execute()
ConnectionEvents.after_execute()
成员
dispatch, do_connect(), do_execute(), do_execute_no_params(), do_executemany(), do_setinputsizes(), handle_error()
类签名
类sqlalchemy.events.DialectEvents (sqlalchemy.event.Events)
attribute dispatch: _Dispatch[_ET] = <sqlalchemy.event.base.DialectEventsDispatch object>
参考 _Dispatch 类。
双向对 _Dispatch._events
method do_connect(dialect: Dialect, conn_rec: ConnectionPoolEntry, cargs: Tuple[Any, ...], cparams: Dict[str, Any]) → DBAPIConnection | None
在建立连接之前接收连接参数。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'do_connect')
def receive_do_connect(dialect, conn_rec, cargs, cparams):
"listen for the 'do_connect' event"
# ... (event handling logic) ...
这个事件很有用,因为它允许处理程序操纵控制 DBAPI connect() 函数将如何调用的 cargs 和/或 cparams 集合。cargs将始终是一个可以原位变异的 Python 列表,而cparams是一个也可以变异的 Python 字典:
e = create_engine("postgresql+psycopg2://user@host/dbname")
@event.listens_for(e, 'do_connect')
def receive_do_connect(dialect, conn_rec, cargs, cparams):
cparams["password"] = "some_password"
事件钩子也可用于完全覆盖connect()的调用,方法是返回一个非None的 DBAPI 连接对象:
e = create_engine("postgresql+psycopg2://user@host/dbname")
@event.listens_for(e, 'do_connect')
def receive_do_connect(dialect, conn_rec, cargs, cparams):
return psycopg2.connect(*cargs, **cparams)
另请参阅
自定义 DBAPI connect() 参数 / 在连接时运行的程序
method do_execute(cursor: DBAPICursor, statement: str, parameters: _DBAPISingleExecuteParams, context: ExecutionContext) → Literal[True] | None
接收一个游标以调用 execute()。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'do_execute')
def receive_do_execute(cursor, statement, parameters, context):
"listen for the 'do_execute' event"
# ... (event handling logic) ...
返回 True 值以阻止进一步调用事件,并指示游标执行已在事件处理程序中发生。
method do_execute_no_params(cursor: DBAPICursor, statement: str, context: ExecutionContext) → Literal[True] | None
接收一个游标以调用没有参数的 execute()。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'do_execute_no_params')
def receive_do_execute_no_params(cursor, statement, context):
"listen for the 'do_execute_no_params' event"
# ... (event handling logic) ...
返回 True 值以阻止进一步调用事件,并指示游标执行已在事件处理程序中发生。
method do_executemany(cursor: DBAPICursor, statement: str, parameters: _DBAPIMultiExecuteParams, context: ExecutionContext) → Literal[True] | None
接收一个游标以调用 executemany()。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'do_executemany')
def receive_do_executemany(cursor, statement, parameters, context):
"listen for the 'do_executemany' event"
# ... (event handling logic) ...
返回 True 值以阻止进一步调用事件,并指示游标执行已在事件处理程序中发生。
method do_setinputsizes(inputsizes: Dict[BindParameter[Any], Any], cursor: DBAPICursor, statement: str, parameters: _DBAPIAnyExecuteParams, context: ExecutionContext) → None
接收可供修改的 setinputsizes 字典。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'do_setinputsizes')
def receive_do_setinputsizes(inputsizes, cursor, statement, parameters, context):
"listen for the 'do_setinputsizes' event"
# ... (event handling logic) ...
当方言使用 DBAPI cursor.setinputsizes() 方法传递关于特定语句参数绑定的信息时,会触发此事件。给定的 inputsizes 字典将包含BindParameter 对象作为键,链接到特定于 DBAPI 的类型对象作为值;对于未绑定的参数,它们将以 None 作为值添加到字典中,这意味着该参数将不会包含在最终的 setinputsizes 调用中。该事件可用于检查和/或记录被绑定的数据类型,并直接修改字典。可以向该字典中添加、修改或删除参数。调用者通常希望检查给定绑定对象的 BindParameter.type 属性,以便对 DBAPI 对象做出决策。
事件之后,inputsizes 字典将转换为适当的数据结构以传递给 cursor.setinputsizes;对于位置绑定参数执行样式,转换为列表;对于命名绑定参数执行样式,转换为字符串参数键到 DBAPI 类型对象的字典。
setinputsizes 钩子整体上仅用于包含标志 use_setinputsizes=True 的方言。使用此标志的方言包括 cx_Oracle、pg8000、asyncpg 和 pyodbc 方言。
注意
与 pyodbc 一起使用时,必须向方言传递 use_setinputsizes 标志,例如:
create_engine("mssql+pyodbc://...", use_setinputsizes=True)
另请参阅
Setinputsizes 支持
新版本 1.2.9 中新增。
另请参阅
使用 setinputsizes 对 cx_Oracle 数据绑定性能进行细粒度控制
method handle_error(exception_context: ExceptionContext) → BaseException | None
拦截Dialect 典型但不限于在 Connection 范围内发出的异常。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'handle_error')
def receive_handle_error(exception_context):
"listen for the 'handle_error' event"
# ... (event handling logic) ...
从版本 2.0 开始更改:DialectEvents.handle_error()事件已移至DialectEvents类中,从ConnectionEvents类中移除,以便它还可以参与使用create_engine.pool_pre_ping参数配置的“预连接”操作。该事件仍通过使用Engine作为事件目标来注册,但请注意,不再支持将Connection用作DialectEvents.handle_error()的事件目标。
这包括由 DBAPI 发出的所有异常,以及 SQLAlchemy 语句调用过程中的其他区域,包括编码错误和其他语句验证错误。调用事件的其他区域包括事务开始和结束、结果行获取、游标创建。
请注意,handle_error()可能随时支持新类型的异常和新的调用场景。使用此事件的代码必须预期在次要版本中存在新的调用模式。
为了支持对应于异常的广泛成员的各种情况,并允许在不向后兼容的情况下扩展事件,所接收的唯一参数是一个ExceptionContext的实例。此对象包含表示异常详细信息的数据成员。
此钩子支持的用例包括:
-
仅用于日志记录和调试目的的只读低级别异常处理
-
建立 DBAPI 连接错误消息是否指示需要重新连接数据库连接,包括某些方言使用的“pre_ping”处理程序
-
在响应特定异常时建立或禁用连接或拥有连接池是否无效或过期
-
异常重写
在失败的操作的游标(如果有)仍处于打开和可访问状态时调用该钩子。可以在此游标上调用特殊的清理操作;SQLAlchemy 将尝试在调用此钩子后关闭此游标。
从 SQLAlchemy 2.0 开始,使用 create_engine.pool_pre_ping 参数启用的“pre_ping”处理程序也将参与 handle_error() 过程,对于那些依赖断开连接代码来检测数据库活动性的方言。请注意,一些方言,如 psycopg、psycopg2 和大多数 MySQL 方言,使用由 DBAPI 提供的本地 ping() 方法,该方法不使用断开连接代码。
在版本 2.0.0 中进行了更改:DialectEvents.handle_error() 事件钩子参与连接池“预先 ping”操作。在此使用中,ExceptionContext.engine 属性将为 None,但是正在使用的 Dialect 可通过 ExceptionContext.dialect 属性始终可用。
在版本 2.0.5 中进行了更改:添加了 ExceptionContext.is_pre_ping 属性,当在连接池的“预先 ping”操作中触发 DialectEvents.handle_error() 事件钩子时,该属性将设置为 True。
在版本 2.0.5 中进行了更改:修复了一个问题,允许 PostgreSQL psycopg 和 psycopg2 驱动程序以及所有 MySQL 驱动程序在连接池“预先 ping”操作期间正确参与 DialectEvents.handle_error() 事件钩子;此前,这些驱动程序的实现对这些驱动程序而言是无效的。
处理程序函数有两个选项来将 SQLAlchemy 构造的异常替换为用户定义的异常。它可以直接引发此新异常,此时所有后续事件监听器都将被绕过,并且异常将在适当的清理完成后被引发:
@event.listens_for(Engine, "handle_error")
def handle_exception(context):
if isinstance(context.original_exception,
psycopg2.OperationalError) and \
"failed" in str(context.original_exception):
raise MySpecialException("failed operation")
警告
因为 DialectEvents.handle_error() 事件专门提供了将异常重新抛出为失败语句引发的最终异常的方法,如果用户定义的事件处理程序本身失败并引发意外异常,则堆栈跟踪将会误导!建议在这里小心编码,并在发生意外异常时使用日志记录和/或内联调试。
或者,可以使用“链接”样式的事件处理,通过使用retval=True修饰符配置处理程序,并从函数返回新的异常实例来使用。在这种情况下,事件处理将继续到下一个处理程序。可以使用ExceptionContext.chained_exception获取“链接”异常:
@event.listens_for(Engine, "handle_error", retval=True)
def handle_exception(context):
if context.chained_exception is not None and \
"special" in context.chained_exception.message:
return MySpecialException("failed",
cause=context.chained_exception)
返回None的处理程序可以在链中使用;当处理程序返回None时,如果有的话,前一个异常实例将保持为传递给下一个处理程序的当前异常。
当引发或返回自定义异常时,SQLAlchemy 将直接引发此新异常,不会被任何 SQLAlchemy 对象包装。如果异常不是sqlalchemy.exc.StatementError的子类,某些功能可能不可用;目前包括 ORM 在自动刷新过程中引发异常时添加有关“自动刷新”的详细提示的功能。
参数:
context – 一个ExceptionContext对象。有关所有可用成员的详细信息,请参阅此类。
另请参阅
支持断开场景下的新数据库错误代码
模式事件
| 对象名称 | 描述 |
|---|---|
| DDLEvents | 为模式对象定义事件监听器,即SchemaItem和其他SchemaEventTarget子类,包括MetaData、Table、Column等。 |
| SchemaEventTarget | 用于DDLEvents事件的目标元素的基类。 |
class sqlalchemy.events.DDLEvents
为模式对象定义事件监听器,即SchemaItem和其他SchemaEventTarget子类,包括MetaData、Table、Column等。
创建/删除事件
当 CREATE 和 DROP 命令发送到数据库时发出的事件。此类别中的事件挂钩包括DDLEvents.before_create(),DDLEvents.after_create(),DDLEvents.before_drop()和DDLEvents.after_drop()。
当使用模式级方法(例如MetaData.create_all()和MetaData.drop_all())时,会发出这些事件。还包括每个对象的 create/drop 方法,如Table.create(),Table.drop(),Index.create(),以及特定于方言的方法,如ENUM.create()。
新功能 2.0 版中:DDLEvents事件挂钩现在适用于非表对象,包括约束、索引和特定于方言的模式类型。
事件挂钩可以直接附加到Table对象或MetaData集合,以及任何可通过单独的 SQL 命令创建和删除的SchemaItem类或对象。此类包括Index,Sequence以及特定于方言的类,例如ENUM。
使用DDLEvents.after_create()事件的示例,其中自定义事件挂钩将在发送CREATE TABLE后在当前连接上发出ALTER TABLE命令:
from sqlalchemy import create_engine
from sqlalchemy import event
from sqlalchemy import Table, Column, Metadata, Integer
m = MetaData()
some_table = Table('some_table', m, Column('data', Integer))
@event.listens_for(some_table, "after_create")
def after_create(target, connection, **kw):
connection.execute(text(
"ALTER TABLE %s SET name=foo_%s" % (target.name, target.name)
))
some_engine = create_engine("postgresql://scott:tiger@host/test")
# will emit "CREATE TABLE some_table" as well as the above
# "ALTER TABLE" statement afterwards
m.create_all(some_engine)
约束对象,如ForeignKeyConstraint、UniqueConstraint、CheckConstraint,也可以订阅这些事件,但通常不会产生事件,因为这些对象通常是内联渲染在一个包含的CREATE TABLE语句中,并且在DROP TABLE语句中隐式地被删除。
对于Index构造,事件钩子将被触发为CREATE INDEX,但是当删除表时,SQLAlchemy 通常不会发出DROP INDEX,因为这再次隐含在DROP TABLE语句中。
新版本 2.0 中:支持SchemaItem对象的创建/删除事件从其先前对MetaData和Table的支持扩展到还包括Constraint和所有子类、Index、Sequence以及一些与类型相关的构造,比如ENUM。
注意
这些事件钩子仅在 SQLAlchemy 的创建/删除方法范围内触发;它们不一定受到诸如alembic之类的工具的支持。
附加事件
附加事件提供了自定义行为的机会,每当一个子模式元素与父元素相关联时,比如当一个Column与其Table相关联时,当一个ForeignKeyConstraint与一个Table相关联时等。这些事件包括DDLEvents.before_parent_attach()和DDLEvents.after_parent_attach()。
反射事件
DDLEvents.column_reflect()事件用于拦截和修改数据库表反射进行时的数据库列的 Python 中定义。
与通用 DDL 一起使用
DDL 事件与DDL类和 DDL 子句结构的ExecutableDDLElement层次密切集成,它们本身适合作为侦听器可调用:
from sqlalchemy import DDL
event.listen(
some_table,
"after_create",
DDL("ALTER TABLE %(table)s SET name=foo_%(table)s")
)
事件传播到 MetaData 复制
对于所有DDLEvent事件,propagate=True关键字参数将确保给定的事件处理程序传播到对象的副本中,当使用Table.to_metadata()方法时会生成这些副本:
from sqlalchemy import DDL
metadata = MetaData()
some_table = Table("some_table", metadata, Column("data", Integer))
event.listen(
some_table,
"after_create",
DDL("ALTER TABLE %(table)s SET name=foo_%(table)s"),
propagate=True
)
new_metadata = MetaData()
new_table = some_table.to_metadata(new_metadata)
上述DDL对象将与some_table和new_table``Table对象的DDLEvents.after_create()事件相关联。
另请参阅
事件
ExecutableDDLElement
DDL
控制 DDL 序列
成员
after_create()、after_drop()、after_parent_attach()、before_create()、before_drop()、before_parent_attach()、column_reflect()、dispatch
类签名
类sqlalchemy.events.DDLEvents(sqlalchemy.event.Events)
method after_create(target: SchemaEventTarget, connection: Connection, **kw: Any) → None
在发出 CREATE 语句后调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeSchemaClassOrObject, 'after_create')
def receive_after_create(target, connection, **kw):
"listen for the 'after_create' event"
# ... (event handling logic) ...
参数:
-
target–事件目标,如
MetaData或Table,但也包括所有创建/删除对象,如Index、Sequence等。版本 2.0 新增:添加对所有
SchemaItem对象的支持。 -
connection– 发出 CREATE 语句或语句的Connection。 -
**kw– 与事件相关的附加关键字参数。此字典的内容可能会在不同版本之间变化,并包括在元数据级事件中生成的表列表、checkfirst 标志以及内部事件使用的其他元素。
listen() 还接受propagate=True修饰符,用于此事件;当为 True 时,监听器函数将为目标对象的任何副本建立,即在使用Table.to_metadata() 生成的那些副本。
method after_drop(target: SchemaEventTarget, connection: Connection, **kw: Any) → None
在发出 DROP 语句后调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeSchemaClassOrObject, 'after_drop')
def receive_after_drop(target, connection, **kw):
"listen for the 'after_drop' event"
# ... (event handling logic) ...
参数:
-
target–事件目标的
SchemaObject,例如MetaData或Table,但也包括所有 create/drop 对象,如Index、Sequence等对象。新版本 2.0 中添加了对所有
SchemaItem对象的支持。 -
connection– 发出 DROP 语句或语句的Connection。 -
**kw– 与事件相关的附加关键字参数。此字典的内容可能会在不同版本之间变化,并包括在元数据级事件中生成的表列表、checkfirst 标志以及内部事件使用的其他元素。
listen() 还接受propagate=True修饰符,用于此事件;当为 True 时,监听器函数将为目标对象的任何副本建立,即在使用Table.to_metadata() 生成的那些副本。
method after_parent_attach(target: SchemaEventTarget, parent: SchemaItem) → None
在SchemaItem与父SchemaItem关联之后调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeSchemaClassOrObject, 'after_parent_attach')
def receive_after_parent_attach(target, parent):
"listen for the 'after_parent_attach' event"
# ... (event handling logic) ...
参数:
-
target– 目标对象 -
parent– 将目标附加到的父级。
listen()还接受propagate=True修饰符用于此事件;当为 True 时,监听函数将为目标对象的任何副本建立,即在使用Table.to_metadata()时生成的那些副本。
method before_create(target: SchemaEventTarget, connection: Connection, **kw: Any) → None
在生成 CREATE 语句之前调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeSchemaClassOrObject, 'before_create')
def receive_before_create(target, connection, **kw):
"listen for the 'before_create' event"
# ... (event handling logic) ...
参数:
-
target–SchemaObject,比如MetaData或Table,还包括所有的创建/删除对象,比如Index、Sequence等,这些对象是事件的目标。2.0 版新增:对所有
SchemaItem对象的支持已添加。 -
connection– 将发出 CREATE 语句或语句的Connection。 -
**kw– 与事件相关的其他关键字参数。此字典的内容可能会在不同版本之间变化,并包括元数据级事件生成的表列表、checkfirst 标志和内部事件使用的其他元素。
listen()接受propagate=True修饰符用于此事件;当为 True 时,监听函数将为目标对象的任何副本建立,即在使用Table.to_metadata()时生成的那些副本。
listen()接受insert=True修饰符用于此事件;当为 True 时,监听函数将被添加到内部事件列表的开头,并在未传递此参数的已注册监听函数之前执行。
method before_drop(target: SchemaEventTarget, connection: Connection, **kw: Any) → None
在生成 DROP 语句之前调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeSchemaClassOrObject, 'before_drop')
def receive_before_drop(target, connection, **kw):
"listen for the 'before_drop' event"
# ... (event handling logic) ...
参数:
-
target–SchemaObject,比如MetaData或Table,还包括所有的创建/删除对象,比如Index、Sequence等,这些对象是事件的目标。2.0 版新增:对所有
SchemaItem对象的支持已添加。 -
connection– 发出 DROP 语句的Connection。 -
**kw– 与事件相关的附加关键字参数。此字典的内容可能因发布而异,包括用于元数据级事件生成表的表列表,checkfirst 标志和内部事件使用的其他元素。
listen()也接受propagate=True修饰符用于此事件;当为 True 时,监听器函数将为目标对象的任何副本建立,即在使用Table.to_metadata()生成的那些副本。
method before_parent_attach(target: SchemaEventTarget, parent: SchemaItem) → None
在将SchemaItem与父SchemaItem关联之前调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeSchemaClassOrObject, 'before_parent_attach')
def receive_before_parent_attach(target, parent):
"listen for the 'before_parent_attach' event"
# ... (event handling logic) ...
参数:
-
target– 目标对象 -
parent– 将目标附加到的父对象。
listen()也接受propagate=True修饰符用于此事件;当为 True 时,监听器函数将为目标对象的任何副本建立,即在使用Table.to_metadata()生成的那些副本。
method column_reflect(inspector: Inspector, table: Table, column_info: ReflectedColumn) → None
在对反射的Table检索每个‘列信息’单元时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeSchemaClassOrObject, 'column_reflect')
def receive_column_reflect(inspector, table, column_info):
"listen for the 'column_reflect' event"
# ... (event handling logic) ...
此事件最容易通过将其应用于特定的MetaData实例来使用,在该实例中,它将对该MetaData中的所有Table对象产生影响,这些对象在反射时进行。
metadata = MetaData()
@event.listens_for(metadata, 'column_reflect')
def receive_column_reflect(inspector, table, column_info):
# receives for all Table objects that are reflected
# under this MetaData
# will use the above event hook
my_table = Table("my_table", metadata, autoload_with=some_engine)
新版本 1.4.0b2 中:DDLEvents.column_reflect()钩子现在也可以应用于MetaData对象,以及它将对与目标MetaData关联的所有Table对象产生影响的MetaData类本身。
它也可以应用于整个Table类:
from sqlalchemy import Table
@event.listens_for(Table, 'column_reflect')
def receive_column_reflect(inspector, table, column_info):
# receives for all Table objects that are reflected
它也可以应用到正在使用Table.listeners参数反射的特定Table上:
t1 = Table(
"my_table",
autoload_with=some_engine,
listeners=[
('column_reflect', receive_column_reflect)
]
)
由方言返回的列信息字典会被传递,并且可以被修改。该字典是由Inspector.get_columns()返回的列表中的每个元素返回的:
name- 列的名称,应用于Column.name参数type- 该列的类型,应该是TypeEngine的一个实例,应用于Column.type参数nullable- 如果列是 NULL 或 NOT NULL 的布尔标志,应用于Column.nullable参数default- 列的服务器默认值。通常将其指定为纯字符串 SQL 表达式,但事件也可以传递一个FetchedValue、DefaultClause或text()对象。应用于Column.server_default参数
在对该字典执行任何操作之前调用事件,并且内容可以被修改;以下其他键可以被添加到字典中以进一步修改如何构造Column:
key- 将用于在.c集合中访问此Column的字符串键;将应用于Column.key参数。也用于 ORM 映射。参见从反射表自动命名列方案一节的示例。quote- 强制或取消强制对列名称进行引用;应用于Column.quote参数。info- 一个包含任意数据的字典,用于跟踪Column,应用于Column.info参数。
listen()还接受propagate=True修改器用于此事件;当为 True 时,监听器函数将为目标对象的任何副本建立,即使用Table.to_metadata()生成的那些副本。
另请参阅
从反射表自动命名方案 - 在 ORM 映射文档中
拦截列定义 - 在 Automap 文档中
反映与数据库无关的类型 - 在反射数据库对象文档中
attribute dispatch: _Dispatch[_ET] = <sqlalchemy.event.base.DDLEventsDispatch object>
回引到 _Dispatch 类。
双向与 _Dispatch._events 相对
class sqlalchemy.events.SchemaEventTarget
作为DDLEvents事件目标的元素的基类。
这包括SchemaItem以及SchemaType。
类签名
类sqlalchemy.events.SchemaEventTarget(sqlalchemy.event.registry.EventTarget)
连接池事件
| 对象名称 | 描述 |
|---|---|
| PoolEvents | Pool的可用事件。 |
| PoolResetState | 描述了一个 DBAPI 连接在传递给PoolEvents.reset()连接池事件时的状态。 |
class sqlalchemy.events.PoolEvents
Pool的可用事件。
这里的方法定义了一个事件的名称以及传递给监听器函数的成员的名称。
例如:
from sqlalchemy import event
def my_on_checkout(dbapi_conn, connection_rec, connection_proxy):
"handle an on checkout event"
event.listen(Pool, 'checkout', my_on_checkout)
除了接受 Pool 类和 Pool 实例外,PoolEvents 还接受 Engine 对象和 Engine 类作为目标,这将解析为给定引擎的 .pool 属性或 Pool 类:
engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test")
# will associate with engine.pool
event.listen(engine, 'checkout', my_on_checkout)
成员
checkin(), checkout(), close(), close_detached(), connect(), detach(), dispatch, first_connect(), invalidate(), reset(), soft_invalidate()
类签名
class sqlalchemy.events.PoolEvents (sqlalchemy.event.Events)
method checkin(dbapi_connection: DBAPIConnection | None, connection_record: ConnectionPoolEntry) → None
当连接返回到池中时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'checkin')
def receive_checkin(dbapi_connection, connection_record):
"listen for the 'checkin' event"
# ... (event handling logic) ...
注意连接可能会关闭,并且如果连接已失效,则可能为 None。对于已分离的连接,不会调用 checkin。(它们不会返回到池中。)
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。
method checkout(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry, connection_proxy: PoolProxiedConnection) → None
当从池中检索到连接时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'checkout')
def receive_checkout(dbapi_connection, connection_record, connection_proxy):
"listen for the 'checkout' event"
# ... (event handling logic) ...
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。 -
connection_proxy–PoolProxiedConnection对象,它将在检出的生命周期内代理 DBAPI 连接的公共接口。
如果引发DisconnectionError,当前连接将被释放并重新获取新连接。所有检出监听器的处理将中止,并使用新连接重新启动。
另请参阅
ConnectionEvents.engine_connect() - 在创建新的Connection时发生的类似事件。
method close(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry) → None
当 DBAPI 连接关闭时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'close')
def receive_close(dbapi_connection, connection_record):
"listen for the 'close' event"
# ... (event handling logic) ...
事件在关闭发生之前发出。
连接关闭可能会失败;通常是因为连接已经关闭。如果关闭操作失败,则连接将被丢弃。
close() 事件对应于仍与池相关联的连接。要拦截分离连接的关闭事件,请使用close_detached()。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。
method close_detached(dbapi_connection: DBAPIConnection) → None
当分离的 DBAPI 连接关闭时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'close_detached')
def receive_close_detached(dbapi_connection):
"listen for the 'close_detached' event"
# ... (event handling logic) ...
事件在关闭发生之前发出。
连接关闭可能会失败;通常是因为连接已经关闭。如果关闭操作失败,则连接将被丢弃。
参数:
dbapi_connection – 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection 属性。
method connect(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry) → None
在为给定的Pool首次创建特定的 DBAPI 连接时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'connect')
def receive_connect(dbapi_connection, connection_record):
"listen for the 'connect' event"
# ... (event handling logic) ...
此事件允许捕获直接在使用 DBAPI 模块级别的.connect()方法以产生新的 DBAPI 连接之后的点。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。
method detach(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry) → None
当 DBAPI 连接与池“分离”时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'detach')
def receive_detach(dbapi_connection, connection_record):
"listen for the 'detach' event"
# ... (event handling logic) ...
此事件在分离后发生。连接不再与给定的连接记录关联。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。
attribute dispatch: _Dispatch[_ET] = <sqlalchemy.event.base.PoolEventsDispatch object>
回溯到 _Dispatch 类。
与 _Dispatch._events 双向对应
method first_connect(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry) → None
第一次从特定Pool检出 DBAPI 连接时仅调用一次此事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'first_connect')
def receive_first_connect(dbapi_connection, connection_record):
"listen for the 'first_connect' event"
# ... (event handling logic) ...
PoolEvents.first_connect() 的原因是基于所有连接使用的设置来确定关于特定一系列数据库连接的信息。由于特定 Pool 指的是单个“创建者”函数(在 Engine 方面指的是使用的 URL 和连接选项),因此通常可以对单个连接进行观察,可以安全地假定关于所有后续连接都有效,例如数据库版本、服务器和客户端编码设置、排序设置等。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。
method invalidate(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry, exception: BaseException | None) → None
当 DBAPI 连接被“失效”时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'invalidate')
def receive_invalidate(dbapi_connection, connection_record, exception):
"listen for the 'invalidate' event"
# ... (event handling logic) ...
每次调用 ConnectionPoolEntry.invalidate() 方法时都会触发此事件,无论是通过 API 使用还是通过“自动失效”触发,不带 soft 标志。
在最终尝试调用连接的.close()之前发生此事件。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。 -
exception– 这次失效的原因对应的异常对象,如果有的话。可能为None。
另请参阅
更多关于失效的信息
method reset(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry, reset_state: PoolResetState) → None
在池化连接发生“重置”操作之前调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'reset')
def receive_reset(dbapi_connection, connection_record, reset_state):
"listen for the 'reset' event"
# ... (event handling logic) ...
# DEPRECATED calling style (pre-2.0, will be removed in a future release)
@event.listens_for(SomeEngineOrPool, 'reset')
def receive_reset(dbapi_connection, connection_record):
"listen for the 'reset' event"
# ... (event handling logic) ...
从 2.0 版本开始更改:PoolEvents.reset() 事件现在接受参数 PoolEvents.reset.dbapi_connection、PoolEvents.reset.connection_record、PoolEvents.reset.reset_state。将在将来的版本中删除接受上述“已弃用”先前参数签名的侦听器函数的支持。
此事件表示在 DBAPI 连接上调用 rollback() 方法之前返回到池中或丢弃时发生。可以使用此事件钩子实现自定义“重置”策略,也可以通过使用 Pool.reset_on_return 参数禁用默认的“重置”行为。
PoolEvents.reset() 和 PoolEvents.checkin() 事件的主要区别在于 PoolEvents.reset() 不仅适用于被返回到池中的池化连接,还适用于使用 Connection.detach() 方法分离的连接以及由于在连接被检入之前进行垃圾回收而被丢弃的 asyncio 连接。
注意,并非所有使用 Connection.invalidate() 使连接无效的事件都会被触发。这些事件可以通过 PoolEvents.soft_invalidate() 和 PoolEvents.invalidate() 事件钩子拦截,所有的“连接关闭”事件都可以通过 PoolEvents.close() 拦截。
PoolEvents.reset() 事件通常在 PoolEvents.checkin() 事件之后发生,除了那些在重置后立即丢弃连接的情况。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。 -
reset_state–PoolResetState实例,提供关于正在重置连接的情况的信息。新版本为 2.0。
另请参阅
返回时重置
ConnectionEvents.rollback()
ConnectionEvents.commit()
method soft_invalidate(dbapi_connection: DBAPIConnection, connection_record: ConnectionPoolEntry, exception: BaseException | None) → None
当 DBAPI 连接要“软无效化”时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngineOrPool, 'soft_invalidate')
def receive_soft_invalidate(dbapi_connection, connection_record, exception):
"listen for the 'soft_invalidate' event"
# ... (event handling logic) ...
每当调用ConnectionPoolEntry.invalidate()方法时,都会发生此事件,带有soft标志。
软无效化指的是在当前连接被检入后,跟踪此连接的连接记录将强制重新连接。在调用时,它不会主动关闭 dbapi_connection。
参数:
-
dbapi_connection– 一个 DBAPI 连接。ConnectionPoolEntry.dbapi_connection属性。 -
connection_record– 管理 DBAPI 连接的ConnectionPoolEntry。 -
exception– 如果有原因导致无效化,则对应此无效化的异常对象。可能为None。
class sqlalchemy.events.PoolResetState
描述了 DBAPI 连接在传递给PoolEvents.reset()连接池事件时的状态。
成员
asyncio_safe,terminate_only,transaction_was_reset
新版本为 2.0.0b3。
attribute asyncio_safe: bool
指示重置操作是否发生在期望存在封闭事件循环的范围内的情况下,用于 asyncio 应用程序。
在连接被垃圾收集时,将为 False。
attribute terminate_only: bool
指示连接是否立即终止并且不被检入到池中。
这发生在无效的连接上,以及未被调用代码清理处理而被垃圾收集的 asyncio 连接上。在后一种情况下,在垃圾收集中无法安全地运行 asyncio 连接操作,因为不一定存在事件循环。
attribute transaction_was_reset: bool
表示如果 DBAPI 连接上的事务已经被Connection对象“重置”。
如果Connection具有事务状态,并且该状态未使用Connection.rollback()或Connection.commit()方法关闭;相反,事务在Connection.close()方法中内联关闭,因此在达到此事件时保证不会存在。
SQL 执行和连接事件
| 对象名称 | 描述 |
|---|---|
| ConnectionEvents | 对于Connection和Engine可用的事件。 |
| DialectEvents | 用于执行替换函数的事件接口。 |
class sqlalchemy.events.ConnectionEvents
对于Connection和Engine可用的事件。
这里的方法定义了事件的名称以及传递给监听器函数的成员的名称。
事件监听器可以与任何Connection或Engine类或实例相关联,例如一个Engine,例如:
from sqlalchemy import event, create_engine
def before_cursor_execute(conn, cursor, statement, parameters, context,
executemany):
log.info("Received statement: %s", statement)
engine = create_engine('postgresql+psycopg2://scott:tiger@localhost/test')
event.listen(engine, "before_cursor_execute", before_cursor_execute)
或使用特定的Connection:
with engine.begin() as conn:
@event.listens_for(conn, 'before_cursor_execute')
def before_cursor_execute(conn, cursor, statement, parameters,
context, executemany):
log.info("Received statement: %s", statement)
当方法被带有语句参数调用时,例如在after_cursor_execute()或before_cursor_execute()中,语句是传输到连接的 DBAPIcursor中准备的确切 SQL 字符串,该连接的Dialect。
before_execute()和before_cursor_execute()事件也可以使用retval=True标志来建立,这允许修改要发送到数据库的语句和参数。 before_cursor_execute()事件在此处特别有用,以添加特定的字符串转换,如注释,到所有执行中:
from sqlalchemy.engine import Engine
from sqlalchemy import event
@event.listens_for(Engine, "before_cursor_execute", retval=True)
def comment_sql_calls(conn, cursor, statement, parameters,
context, executemany):
statement = statement + " -- some comment"
return statement, parameters
注意
ConnectionEvents可以建立在任何组合的Engine、Connection,以及这些类的实例上。 对于给定的Connection实例,所有四个作用域的事件都将触发。 但是,出于性能原因,Connection对象在实例化时确定其父Engine是否已建立事件侦听器。 在依赖的Connection实例实例化之后,添加到Engine类或Engine实例的事件侦听器通常不会在该Connection实例上可用。 新添加的侦听器将取代对父Engine类或实例建立事件侦听器后创建的Connection实例。
参数:
retval=False – 仅适用于before_execute()和before_cursor_execute()事件。 当值为 True 时,用户定义的事件函数必须有一个返回值,即替换给定语句和参数的参数元组。 查看这些方法以获取特定返回参数的描述。
成员
after_cursor_execute(), after_execute(), before_cursor_execute(), before_execute(), begin(), begin_twophase(), commit(), commit_twophase(), dispatch, engine_connect(), engine_disposed(), prepare_twophase(), release_savepoint(), rollback(), rollback_savepoint(), rollback_twophase(), savepoint(), set_connection_execution_options(), set_engine_execution_options()
类签名
类sqlalchemy.events.ConnectionEvents (sqlalchemy.event.Events)
method after_cursor_execute(conn: Connection, cursor: DBAPICursor, statement: str, parameters: _DBAPIAnyExecuteParams, context: ExecutionContext | None, executemany: bool) → None
在执行后拦截低级游标execute()事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'after_cursor_execute')
def receive_after_cursor_execute(conn, cursor, statement, parameters, context, executemany):
"listen for the 'after_cursor_execute' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
cursor– DBAPI 游标对象。如果语句是 SELECT,则将有待处理的结果,但不应消耗这些结果,因为它们将被CursorResult所需。 -
statement– 字符串 SQL 语句,如传递给 DBAPI -
parameters– 字典、元组或传递给 DBAPIcursor的execute()或executemany()方法的参数列表。在某些情况下可能为None。 -
context– 正在使用的ExecutionContext对象。可能为None。 -
executemany– 布尔值,如果为True,则这是一个executemany()调用,如果为False,则这是一个execute()调用。
method after_execute(conn: Connection, clauseelement: Executable, multiparams: _CoreMultiExecuteParams, params: _CoreSingleExecuteParams, execution_options: _ExecuteOptions, result: Result[Any]) → None
在执行后拦截高级execute()事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'after_execute')
def receive_after_execute(conn, clauseelement, multiparams, params, execution_options, result):
"listen for the 'after_execute' event"
# ... (event handling logic) ...
# DEPRECATED calling style (pre-1.4, will be removed in a future release)
@event.listens_for(SomeEngine, 'after_execute')
def receive_after_execute(conn, clauseelement, multiparams, params, result):
"listen for the 'after_execute' event"
# ... (event handling logic) ...
从版本 1.4 开始更改: ConnectionEvents.after_execute() 事件现在接受参数 ConnectionEvents.after_execute.conn, ConnectionEvents.after_execute.clauseelement, ConnectionEvents.after_execute.multiparams, ConnectionEvents.after_execute.params, ConnectionEvents.after_execute.execution_options, ConnectionEvents.after_execute.result。支持接受先前参数签名的监听器函数将在未来的版本中删除。
参数:
-
conn–Connection对象 -
clauseelement– SQL 表达式构造,Compiled实例,或传递给Connection.execute()的字符串语句。 -
multiparams– 多个参数集,一个字典列表。 -
params– 单个参数集,一个字典。 -
execution_options–传递给语句的执行选项字典,如果有的话。这是将要使用的所有选项的合并,包括语句、连接和传递给方法本身的那些选项,用于执行 2.0 风格。
-
result– 执行生成的CursorResult。
method before_cursor_execute(conn: Connection, cursor: DBAPICursor, statement: str, parameters: _DBAPIAnyExecuteParams, context: ExecutionContext | None, executemany: bool) → Tuple[str, _DBAPIAnyExecuteParams] | None
在执行之前拦截低级别的游标 execute() 事件,接收要针对游标调用的字符串 SQL 语句和 DBAPI 特定参数列表。
示��参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, parameters, context, executemany):
"listen for the 'before_cursor_execute' event"
# ... (event handling logic) ...
这个事件非常适合用于日志记录以及对 SQL 字符串的后期修改。对于那些特定于目标后端的参数修改来说,它不太理想。
这个事件可以选择使用 retval=True 标志来建立。在这种情况下,statement 和 parameters 参数应该作为一个二元组返回:
@event.listens_for(Engine, "before_cursor_execute", retval=True)
def before_cursor_execute(conn, cursor, statement,
parameters, context, executemany):
# do something with statement, parameters
return statement, parameters
参见 ConnectionEvents 中的示例。
参数:
-
conn–Connection对象 -
cursor– DBAPI 游标对象 -
statement– 要传递给 DBAPI 的字符串 SQL 语句 -
parameters– 正在传递给 DBAPIcursor的execute()或executemany()方法的参数的字典、元组或列表。在某些情况下可能为None。 -
context–ExecutionContext对象正在使用。可能为None。 -
executemany– 布尔值,如果为True,则这是一个executemany()调用,如果为False,则这是一个execute()调用。
另请参阅
before_execute()
after_cursor_execute()
method before_execute(conn: Connection, clauseelement: Executable, multiparams: _CoreMultiExecuteParams, params: _CoreSingleExecuteParams, execution_options: _ExecuteOptions) → Tuple[Executable, _CoreMultiExecuteParams, _CoreSingleExecuteParams] | None
拦截高级 execute() 事件,接收未编译的 SQL 构造和其他对象,在渲染成 SQL 之前。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'before_execute')
def receive_before_execute(conn, clauseelement, multiparams, params, execution_options):
"listen for the 'before_execute' event"
# ... (event handling logic) ...
# DEPRECATED calling style (pre-1.4, will be removed in a future release)
@event.listens_for(SomeEngine, 'before_execute')
def receive_before_execute(conn, clauseelement, multiparams, params):
"listen for the 'before_execute' event"
# ... (event handling logic) ...
自 1.4 版更改:ConnectionEvents.before_execute() 事件现在接受参数 ConnectionEvents.before_execute.conn、ConnectionEvents.before_execute.clauseelement、ConnectionEvents.before_execute.multiparams、ConnectionEvents.before_execute.params、ConnectionEvents.before_execute.execution_options。对于接受上述先前参数签名的监听函数,将在将来的版本中移除。
此事件非常适用于调试 SQL 编译问题以及对发送到数据库的参数进行早期处理,因为此处的参数列表将保持一致的格式。
此事件可以选择使用 retval=True 标志来建立。在这种情况下,clauseelement、multiparams 和 params 参数应作为三元组返回:
@event.listens_for(Engine, "before_execute", retval=True)
def before_execute(conn, clauseelement, multiparams, params):
# do something with clauseelement, multiparams, params
return clauseelement, multiparams, params
参数:
-
conn–Connection对象 -
clauseelement– SQL 表达式构造,Compiled实例,或传递给Connection.execute()的字符串语句。 -
multiparams– 多参数集合,一个字典列表。 -
params– 单参数集合,一个字典。 -
execution_options–执行选项字典随语句一起传递,如果有的话。这是将被使用的所有选项的合并,包括语句、连接和传递给方法本身的 2.0 执行风格的选项。
另请参阅
before_cursor_execute()
method begin(conn: Connection) → None
拦截begin()事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'begin')
def receive_begin(conn):
"listen for the 'begin' event"
# ... (event handling logic) ...
参数:
conn – Connection 对象
method begin_twophase(conn: Connection, xid: Any) → None
拦截begin_twophase()事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'begin_twophase')
def receive_begin_twophase(conn, xid):
"listen for the 'begin_twophase' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
xid– 两阶段 XID 标识符
method commit(conn: Connection) → None
拦截由Transaction发起的commit()事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'commit')
def receive_commit(conn):
"listen for the 'commit' event"
# ... (event handling logic) ...
请注意,如果reset_on_return标志设置为值'commit',Pool也可能在检入时“自动提交”DBAPI 连接。要拦截此提交,请使用PoolEvents.reset()钩子。
参数:
conn – Connection 对象
method commit_twophase(conn: Connection, xid: Any, is_prepared: bool) → None
拦截commit_twophase()事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'commit_twophase')
def receive_commit_twophase(conn, xid, is_prepared):
"listen for the 'commit_twophase' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
xid– 两阶段 XID 标识符 -
is_prepared– 布尔值,指示是否调用了TwoPhaseTransaction.prepare()。
attribute dispatch: _Dispatch[_ET] = <sqlalchemy.event.base.ConnectionEventsDispatch object>
引用回 _Dispatch 类。
双向针对 _Dispatch._events
method engine_connect(conn: Connection) → None
拦截创建新的Connection。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'engine_connect')
def receive_engine_connect(conn):
"listen for the 'engine_connect' event"
# ... (event handling logic) ...
# DEPRECATED calling style (pre-2.0, will be removed in a future release)
@event.listens_for(SomeEngine, 'engine_connect')
def receive_engine_connect(conn, branch):
"listen for the 'engine_connect' event"
# ... (event handling logic) ...
2.0 版中的变化:ConnectionEvents.engine_connect()事件现在接受参数ConnectionEvents.engine_connect.conn。支持接受上面列出的“已弃用”的先前参数签名的监听器函数将在将来的版本中移除。
该事件通常作为调用Engine.connect()方法的直接结果。
它与PoolEvents.connect()方法不同,后者指的是在 DBAPI 级别实际连接到数据库;DBAPI 连接可能会被池化并重复使用于许多操作。相比之下,此事件仅指生产一个围绕此类 DBAPI 连接的更高级别Connection包装器。
它还与PoolEvents.checkout()事件不同,后者特定于Connection对象,而不是PoolEvents.checkout()处理的 DBAPI 连接,尽管此 DBAPI 连接可通过Connection.connection属性在此处获取。但请注意,在单个Connection对象的生命周期内,实际上可以有多个PoolEvents.checkout()事件,如果该Connection被使无效并重新建立。
参数:
conn – Connection 对象。
另请参见
PoolEvents.checkout() 是针对单个 DBAPI 连接的低级别池检出事件。
method engine_disposed(engine: Engine) → None
拦截Engine.dispose()方法调用时。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'engine_disposed')
def receive_engine_disposed(engine):
"listen for the 'engine_disposed' event"
# ... (event handling logic) ...
Engine.dispose()方法指示引擎“处理”其连接池(例如Pool),并用新的替换它。处理旧池的效果是关闭现有的已检入连接。新池在首次使用之前不会建立任何新连接。
可以使用此事件指示应清理与Engine相关的资源,需要注意的是Engine仍然可以用于新请求,此时会重新获取连接资源。
method prepare_twophase(conn: Connection, xid: Any) → None
拦截 prepare_twophase() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'prepare_twophase')
def receive_prepare_twophase(conn, xid):
"listen for the 'prepare_twophase' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
xid– 两阶段 XID 标识符
method release_savepoint(conn: Connection, name: str, context: None) → None
拦截 release_savepoint() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'release_savepoint')
def receive_release_savepoint(conn, name, context):
"listen for the 'release_savepoint' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
name– 用于保存点的指定名称。 -
context– 未使用
method rollback(conn: Connection) → None
拦截 rollback() 事件,由 Transaction 发起。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'rollback')
def receive_rollback(conn):
"listen for the 'rollback' event"
# ... (event handling logic) ...
注意,如果 reset_on_return 标志设置为其默认值 'rollback',则 Pool 也会在归还时“自动回滚” DBAPI 连接。要拦截此回滚,请使用 PoolEvents.reset() 钩子。
参数:
conn – Connection 对象
另请参阅
PoolEvents.reset()
method rollback_savepoint(conn: Connection, name: str, context: None) → None
拦截 rollback_savepoint() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'rollback_savepoint')
def receive_rollback_savepoint(conn, name, context):
"listen for the 'rollback_savepoint' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
name– 用于保存点的指定名称。 -
context– 未使用
method rollback_twophase(conn: Connection, xid: Any, is_prepared: bool) → None
拦截 rollback_twophase() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'rollback_twophase')
def receive_rollback_twophase(conn, xid, is_prepared):
"listen for the 'rollback_twophase' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
xid– 两阶段 XID 标识符 -
is_prepared– 布尔值,指示是否调用了TwoPhaseTransaction.prepare()。
method savepoint(conn: Connection, name: str) → None
拦截 savepoint() 事件。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'savepoint')
def receive_savepoint(conn, name):
"listen for the 'savepoint' event"
# ... (event handling logic) ...
参数:
-
conn–Connection对象 -
name– 用于保存点的指定名称。
method set_connection_execution_options(conn: Connection, opts: Dict[str, Any]) → None
拦截 Connection.execution_options() 方法调用时。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'set_connection_execution_options')
def receive_set_connection_execution_options(conn, opts):
"listen for the 'set_connection_execution_options' event"
# ... (event handling logic) ...
此方法在新的 Connection 生成后被调用,带有新更新的执行选项集合,但在 Dialect 对这些新选项采取任何操作之前。
请注意,当从其父Engine继承执行选项的新Connection生成时,不会调用此方法;要拦截此条件,请使用ConnectionEvents.engine_connect()事件。
参数:
-
conn– 新复制的Connection对象 -
opts–传递给
Connection.execution_options()方法的选项字典。此字典可以就地修改以影响最终生效的选项。2.0 版中的新功能:
opts字典可以就地修改。
另请参阅
ConnectionEvents.set_engine_execution_options() - 当调用Engine.execution_options()时触发的事件。
method set_engine_execution_options(engine: Engine, opts: Dict[str, Any]) → None
当调用Engine.execution_options()方法时拦截。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'set_engine_execution_options')
def receive_set_engine_execution_options(engine, opts):
"listen for the 'set_engine_execution_options' event"
# ... (event handling logic) ...
Engine.execution_options()方法会生成一个存储新选项的Engine的浅拷贝。这个新的Engine会传递到这里。这个方法的一个特定应用是向给定的Engine添加一个ConnectionEvents.engine_connect()事件处理程序,该处理程序将执行一些特定于这些执行选项的每个Connection任务。
参数:
-
conn– 新复制的Engine对象 -
opts–传递给
Connection.execution_options()方法的选项字典。此字典可以就地修改以影响最终生效的选项。2.0 版中的新功能:
opts字典可以就地修改。
另请参阅
ConnectionEvents.set_connection_execution_options() - 当调用 Connection.execution_options() 时调用的事件。
class sqlalchemy.events.DialectEvents
执行替换函数的事件接口。
这些事件允许直接对与 DBAPI 交互的关键方言函数进行检测和替换。
注意
DialectEvents 钩子应被视为半公开和实验性质。这些钩子不适用于一般用途,仅适用于需要将复杂的 DBAPI 机制重新注入现有方言的情况。对于一般用途的语句拦截事件,请使用 ConnectionEvents 接口。
另请参阅
ConnectionEvents.before_cursor_execute()
ConnectionEvents.before_execute()
ConnectionEvents.after_cursor_execute()
ConnectionEvents.after_execute()
成员
dispatch, do_connect(), do_execute(), do_execute_no_params(), do_executemany(), do_setinputsizes(), handle_error()
类签名
类 sqlalchemy.events.DialectEvents (sqlalchemy.event.Events)
attribute dispatch: _Dispatch[_ET] = <sqlalchemy.event.base.DialectEventsDispatch object>
参考回到 _Dispatch 类。
双向对抗 _Dispatch._events
method do_connect(dialect: Dialect, conn_rec: ConnectionPoolEntry, cargs: Tuple[Any, ...], cparams: Dict[str, Any]) → DBAPIConnection | None
在建立连接之前接收连接参数。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'do_connect')
def receive_do_connect(dialect, conn_rec, cargs, cparams):
"listen for the 'do_connect' event"
# ... (event handling logic) ...
这个事件非常有用,因为它允许处理程序操作控制如何调用 DBAPI connect() 函数的 cargs 和/或 cparams 集合。cargs 将始终是一个可以原地变异的 Python 列表,cparams 是一个也可以被变异的 Python 字典:
e = create_engine("postgresql+psycopg2://user@host/dbname")
@event.listens_for(e, 'do_connect')
def receive_do_connect(dialect, conn_rec, cargs, cparams):
cparams["password"] = "some_password"
事件钩子也可以完全覆盖对 connect() 的调用,通过返回一个非 None 的 DBAPI 连接对象:
e = create_engine("postgresql+psycopg2://user@host/dbname")
@event.listens_for(e, 'do_connect')
def receive_do_connect(dialect, conn_rec, cargs, cparams):
return psycopg2.connect(*cargs, **cparams)
另请参阅
自定义 DBAPI connect() 参数 / on-connect routines
method do_execute(cursor: DBAPICursor, statement: str, parameters: _DBAPISingleExecuteParams, context: ExecutionContext) → Literal[True] | None
接收一个游标以调用 execute()。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'do_execute')
def receive_do_execute(cursor, statement, parameters, context):
"listen for the 'do_execute' event"
# ... (event handling logic) ...
返回 True 以阻止进一步调用事件,并指示光标执行已经在事件处理程序中发生。
method do_execute_no_params(cursor: DBAPICursor, statement: str, context: ExecutionContext) → Literal[True] | None
接收一个游标以调用没有参数的 execute()。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'do_execute_no_params')
def receive_do_execute_no_params(cursor, statement, context):
"listen for the 'do_execute_no_params' event"
# ... (event handling logic) ...
返回 True 以阻止进一步调用事件,并指示光标执行已经在事件处理程序中发生。
method do_executemany(cursor: DBAPICursor, statement: str, parameters: _DBAPIMultiExecuteParams, context: ExecutionContext) → Literal[True] | None
接收一个游标以调用 executemany()。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'do_executemany')
def receive_do_executemany(cursor, statement, parameters, context):
"listen for the 'do_executemany' event"
# ... (event handling logic) ...
返回 True 以阻止进一步调用事件,并指示光标执行已经在事件处理程序中发生。
method do_setinputsizes(inputsizes: Dict[BindParameter[Any], Any], cursor: DBAPICursor, statement: str, parameters: _DBAPIAnyExecuteParams, context: ExecutionContext) → None
接收 setinputsizes 字典以进行可能的修改。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'do_setinputsizes')
def receive_do_setinputsizes(inputsizes, cursor, statement, parameters, context):
"listen for the 'do_setinputsizes' event"
# ... (event handling logic) ...
在方言使用 DBAPI cursor.setinputsizes() 方法传递有关特定语句的参数绑定的情况下,将发出此事件。给定的 inputsizes 字典将包含 BindParameter 对象作为键,链接到 DBAPI 特定类型对象作为值;对于未绑定的参数,将使用 None 作为值将其添加到字典中,这意味着该参数不会包含在最终的 setinputsizes 调用中。可以使用此事件来检查和/或记录正在绑定的数据类型,以及直接修改字典。可以向此字典添加、修改或删除参数。调用者通常会想要检查给定绑定对象的 BindParameter.type 属性,以便对 DBAPI 对象做出决策。
在事件之后,inputsizes 字典将转换为适当的数据结构,以传递给 cursor.setinputsizes;对于位置绑定参数执行样式,将转换为列表,对于命名绑定参数执行样式,将转换为字符串参数键到 DBAPI 类型对象的字典。
setinputsizes 钩子通常仅在包括标志 use_setinputsizes=True 的方言中使用。使用此功能的方言包括 cx_Oracle、pg8000、asyncpg 和 pyodbc 方言。
注意
对于使用 pyodbc,必须将 use_setinputsizes 标志传递给方言,例如:
create_engine("mssql+pyodbc://...", use_setinputsizes=True)
另请参阅
setinputsizes 支持
新版本 1.2.9 中的新功能。
另请参阅
通过 setinputsizes 对 cx_Oracle 数据绑定性能进行细粒度控制
method handle_error(exception_context: ExceptionContext) → BaseException | None
拦截由 Dialect 处理的所有异常,通常但不限于在 Connection 范围内发出的异常。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeEngine, 'handle_error')
def receive_handle_error(exception_context):
"listen for the 'handle_error' event"
# ... (event handling logic) ...
从版本 2.0 起更改:DialectEvents.handle_error() 事件已移至 DialectEvents 类,从 ConnectionEvents 类移动,以便它还可以参与由 create_engine.pool_pre_ping 参数配置的“pre ping”操作。该事件仍通过使用 Engine 作为事件目标进行注册,但请注意,不再支持将 Connection 用作 DialectEvents.handle_error() 的事件目标。
这包括由 DBAPI 发出的所有异常以及 SQLAlchemy 的语句调用过程中,包括编码错误和其他语句验证错误。调用事件的其他区域包括事务开始和结束,结果行获取,游标创建。
请注意,handle_error() 可能在 任何时候 支持新类型的异常和新的调用场景。使用此事件的代码必须预期在次要版本中存在新的调用模式。
为了支持对应于异常的各种成员,并且允许事件的可扩展性而不会导致向后不兼容,唯一接收的参数是ExceptionContext的实例。此对象包含表示异常详细信息的数据成员。
此钩子支持的用例包括:
-
用于记录和调试目的的只读低级异常处理
-
确定 DBAPI 连接错误消息是否表明需要重新连接数据库,包括一些方言中使用的“pre_ping”处理程序
-
确定或禁用特定异常响应中连接或拥有的连接池是否无效或过期
-
异常重写
在失败操作的游标(如果有)仍然打开且可访问时调用该钩子。可以在此游标上调用特殊的清理操作;SQLAlchemy 将在调用此钩子后尝试关闭此游标。
自 SQLAlchemy 2.0 起,使用 create_engine.pool_pre_ping 参数启用的“pre_ping”处理程序也将参与 handle_error() 过程,对于依赖于断开连接代码来检测数据库存活性的那些方言。请注意,某些方言,如 psycopg、psycopg2 和大多数 MySQL 方言,使用由 DBAPI 提供的本机 ping() 方法,该方法不使用断开连接代码。
在 2.0.0 版本中进行了更改:DialectEvents.handle_error() 事件钩子参与连接池“预检”操作。在此用法中,ExceptionContext.engine 属性将为 None,但是正在使用的 Dialect 始终可通过 ExceptionContext.dialect 属性获得。
在 2.0.5 版本中进行了更改:添加了 ExceptionContext.is_pre_ping 属性,当在连接池预检操作中触发 DialectEvents.handle_error() 事件钩子时,该属性将设置为 True。
在 2.0.5 版本中进行了更改:修复了一个问题,允许 PostgreSQL psycopg 和 psycopg2 驱动程序,以及所有 MySQL 驱动程序,在连接池“预检”操作期间正确参与 DialectEvents.handle_error() 事件钩子;先前,这些驱动程序的实现是不工作的。
处理程序函数有两个选项,可以将 SQLAlchemy 构造的异常替换为用户定义的异常。它可以直接引发这个新异常,这样所有后续的事件监听器都会被绕过,并且在适当的清理后引发异常:
@event.listens_for(Engine, "handle_error")
def handle_exception(context):
if isinstance(context.original_exception,
psycopg2.OperationalError) and \
"failed" in str(context.original_exception):
raise MySpecialException("failed operation")
警告
因为 DialectEvents.handle_error() 事件特别提供了将异常重新抛出为失败语句引发的最终异常,如果用户定义的事件处理程序本身失败并抛出意外异常,则堆栈跟踪将是误导性的;堆栈跟踪可能不会显示实际失败的代码行!建议在此处小心编码,并在发生意外异常时使用日志记录和/或内联调试。
或者,可以使用“链接”风格的事件处理,通过使用retval=True修饰符配置处理程序,并从函数返回新的异常实例。在这种情况下,事件处理将继续到下一个处理程序。可使用ExceptionContext.chained_exception获取“链接”异常:
@event.listens_for(Engine, "handle_error", retval=True)
def handle_exception(context):
if context.chained_exception is not None and \
"special" in context.chained_exception.message:
return MySpecialException("failed",
cause=context.chained_exception)
返回None的处理程序可以在链中使用;当处理程序返回None时,如果有的话,前一个异常实例将保持为传递给下一个处理程序的当前异常。
当引发或返回自定义异常时,SQLAlchemy 将原样引发此新异常,不会被任何 SQLAlchemy 对象包装。如果异常不是sqlalchemy.exc.StatementError的子类,则某些功能可能不可用;目前包括 ORM 在自动刷新过程中引发异常时添加有关“自动刷新”的详细提示的功能。
参数:
context – 一个ExceptionContext对象。有关所有可用成员的详细信息,请参阅此类。
另请参见
支持断开连接场景的新数据库错误代码
模式事件
| 对象名称 | 描述 |
|---|---|
| DDL 事件 | 为模式对象定义事件监听器,即SchemaItem和其他SchemaEventTarget子类,包括MetaData、Table、Column等。 |
| SchemaEventTarget | 用于DDL 事件事件目标的元素的基类。 |
class sqlalchemy.events.DDLEvents
为模式对象定义事件监听器,即SchemaItem和其他SchemaEventTarget子类,包括MetaData、Table、Column等。
创建/删除事件
在将 CREATE 和 DROP 命令发送到数据库时发出的事件。此类别中的事件钩子包括DDLEvents.before_create()、DDLEvents.after_create()、DDLEvents.before_drop()和DDLEvents.after_drop()。
当使用架构级别方法时,例如MetaData.create_all()和MetaData.drop_all()时会发出这些事件。还包括每个对象的创建/删除方法,例如Table.create()、Table.drop()、Index.create(),以及方言特定的方法,例如ENUM.create()。
版本 2.0 中的新功能:DDLEvents事件钩子现在适用于非表对象,包括约束、索引和方言特定的架构类型。
事件钩子可以直接附加到Table对象或MetaData集合,以及任何可以使用独立的 SQL 命令单独创建和删除的SchemaItem类或对象。这样的类包括Index、Sequence以及方言特定的类,例如ENUM。
使用DDLEvents.after_create()事件的示例,在当前连接上自定义事件钩子将在发出CREATE TABLE后发出ALTER TABLE命令:
from sqlalchemy import create_engine
from sqlalchemy import event
from sqlalchemy import Table, Column, Metadata, Integer
m = MetaData()
some_table = Table('some_table', m, Column('data', Integer))
@event.listens_for(some_table, "after_create")
def after_create(target, connection, **kw):
connection.execute(text(
"ALTER TABLE %s SET name=foo_%s" % (target.name, target.name)
))
some_engine = create_engine("postgresql://scott:tiger@host/test")
# will emit "CREATE TABLE some_table" as well as the above
# "ALTER TABLE" statement afterwards
m.create_all(some_engine)
诸如ForeignKeyConstraint、UniqueConstraint、CheckConstraint等约束对象也可以订阅这些事件,但是它们通常不会产生事件,因为这些对象通常被嵌入在包含的CREATE TABLE语句中,并且隐含地从DROP TABLE语句中删除。
对于Index构造,当执行CREATE INDEX时会触发事件钩子,但是当删除表时 SQLAlchemy 通常不会触发DROP INDEX,因为这在DROP TABLE语句中是隐含的。
从版本 2.0 开始:对于SchemaItem对象的支持已经从其之前对MetaData和Table的支持扩展到还包括Constraint及其所有子类、Index、Sequence以及一些与类型相关的构造,例如ENUM。
注意
这些事件钩子只在 SQLAlchemy 的 create/drop 方法范围内触发;并不一定被诸如alembic等工具支持。
附加事件
附加事件用于在子模式元素与父元素关联时自定义行为,例如当Column与其Table关联,当ForeignKeyConstraint与Table关联等。这些事件包括DDLEvents.before_parent_attach()和DDLEvents.after_parent_attach()。
反射事件
DDLEvents.column_reflect() 事件用于拦截和修改数据库表反射进行时的数据库列的 Python 定义。
与通用 DDL 一起使用
DDL 事件与DDL类和 DDL 子句构造的ExecutableDDLElement层次结构密切集成,它们本身适用于监听器可调用:
from sqlalchemy import DDL
event.listen(
some_table,
"after_create",
DDL("ALTER TABLE %(table)s SET name=foo_%(table)s")
)
事件传播到 MetaData 副本
对于所有DDLEvent事件,propagate=True关键字参数将确保给定事件处理程序传播到对象的副本,当使用Table.to_metadata()方法时会创建这些副本:
from sqlalchemy import DDL
metadata = MetaData()
some_table = Table("some_table", metadata, Column("data", Integer))
event.listen(
some_table,
"after_create",
DDL("ALTER TABLE %(table)s SET name=foo_%(table)s"),
propagate=True
)
new_metadata = MetaData()
new_table = some_table.to_metadata(new_metadata)
上述DDL对象将与some_table和new_table``Table对象的DDLEvents.after_create()事件相关联。
另请参阅
事件
ExecutableDDLElement
DDL
控制 DDL 序列
成员
after_create(), after_drop(), after_parent_attach(), before_create(), before_drop(), before_parent_attach(), column_reflect(), dispatch
类签名
类sqlalchemy.events.DDLEvents(sqlalchemy.event.Events)
method after_create(target: SchemaEventTarget, connection: Connection, **kw: Any) → None
在发出 CREATE 语句后调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeSchemaClassOrObject, 'after_create')
def receive_after_create(target, connection, **kw):
"listen for the 'after_create' event"
# ... (event handling logic) ...
参数:
-
target–SchemaObject,比如MetaData或Table,但也包括所有创建/删除对象,如Index、Sequence等,这些对象是事件的目标。新版本 2.0 中:添加了对所有
SchemaItem对象的支持。 -
connection–Connection,在其中发出了 CREATE 语句或语句。 -
**kw– 与事件相关的额外关键字参数。此字典的内容可能在不同版本之间变化,并包括在元数据级事件中生成的表列表、checkfirst 标志和其他内部事件使用的元素。
listen() 也接受 propagate=True 修饰符用于此事件;当为 True 时,监听器函数将被建立为目标对象的任何副本,即在使用 Table.to_metadata() 生成的那些副本。
method after_drop(target: SchemaEventTarget, connection: Connection, **kw: Any) → None
在发出 DROP 语句后调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeSchemaClassOrObject, 'after_drop')
def receive_after_drop(target, connection, **kw):
"listen for the 'after_drop' event"
# ... (event handling logic) ...
参数:
-
target–SchemaObject,如MetaData或Table,但也包括所有创建/删除对象,如Index、Sequence等,是事件的目标对象。新版本 2.0 中:添加了对所有
SchemaItem对象的支持。 -
connection–Connection,在其中发出了 DROP 语句或语句。 -
**kw– 与事件相关的额外关键字参数。此字典的内容可能在不同版本之间变化,并包括在元数据级事件中生成的表列表、checkfirst 标志和其他内部事件使用的元素。
listen() 也接受 propagate=True 修饰符用于此事件;当为 True 时,监听器函数将被建立为目标对象的任何副本,即在使用 Table.to_metadata() 生成的那些副本。
method after_parent_attach(target: SchemaEventTarget, parent: SchemaItem) → None
在将 SchemaItem 与父 SchemaItem 关联后调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeSchemaClassOrObject, 'after_parent_attach')
def receive_after_parent_attach(target, parent):
"listen for the 'after_parent_attach' event"
# ... (event handling logic) ...
参数:
-
target– 目标对象 -
parent– 要将目标附加到的父级。
listen() 还接受 propagate=True 修改器用于此事件;当为 True 时,监听器函数将为目标对象的任何副本建立,即当使用 Table.to_metadata() 生成这些副本时。
method before_create(target: SchemaEventTarget, connection: Connection, **kw: Any) → None
在发出 CREATE 语句之前调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeSchemaClassOrObject, 'before_create')
def receive_before_create(target, connection, **kw):
"listen for the 'before_create' event"
# ... (event handling logic) ...
参数:
-
target–SchemaObject,如MetaData或Table,但也包括所有创建/删除对象,如Index、Sequence等,是事件目标的对象。版本 2.0 新增支持所有
SchemaItem对象。 -
connection– 将发出 CREATE 语句的Connection。 -
**kw– 与事件相关的额外关键字参数。该字典的内容可能因版本而异,包括生成元数据级事件的表列表、checkfirst 标志和其他内部事件使用的元素。
listen() 接受 propagate=True 修改器用于此事件;当为 True 时,监听器函数将为目标对象的任何副本建立,即当使用 Table.to_metadata() 生成这些副本时。
listen() 接受 insert=True 修改器用于此事件;当为 True 时,监听器函数将在发现时被添加到内部事件列表之前,并在不传递此参数的已注册监听器函数之前执行。
method before_drop(target: SchemaEventTarget, connection: Connection, **kw: Any) → None
在发出 DROP 语句之前调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeSchemaClassOrObject, 'before_drop')
def receive_before_drop(target, connection, **kw):
"listen for the 'before_drop' event"
# ... (event handling logic) ...
参数:
-
target–SchemaObject,如MetaData或Table,但也包括所有创建/删除对象,如Index、Sequence等,是事件目标的对象。版本 2.0 新增支持所有
SchemaItem对象。 -
connection– 将发出 DROP 语句或语句的Connection。 -
**kw– 与事件相关的其他关键字参数。此字典的内容可能在不同版本中有所变化,包括为元数据级事件生成的表列表、checkfirst 标志以及内部事件使用的其他元素。
listen()也接受propagate=True修饰符用于此事件;当为 True 时,监听函数将为目标对象的任何副本建立,即当使用Table.to_metadata()生成副本时。
method before_parent_attach(target: SchemaEventTarget, parent: SchemaItem) → None
在将SchemaItem与父SchemaItem关联之前调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeSchemaClassOrObject, 'before_parent_attach')
def receive_before_parent_attach(target, parent):
"listen for the 'before_parent_attach' event"
# ... (event handling logic) ...
参数:
-
target– 目标对象 -
parent– 要将目标附加到的父级。
listen()也接受propagate=True修饰符用于此事件;当为 True 时,监听函数将为目标对象的任何副本建立,即当使用Table.to_metadata()生成副本时。
method column_reflect(inspector: Inspector, table: Table, column_info: ReflectedColumn) → None
在反射Table时检索每个‘column info’单元时调用。
示例参数形式:
from sqlalchemy import event
@event.listens_for(SomeSchemaClassOrObject, 'column_reflect')
def receive_column_reflect(inspector, table, column_info):
"listen for the 'column_reflect' event"
# ... (event handling logic) ...
此事件最容易通过将其应用于特定的MetaData实例来使用,在那里它将对该MetaData中的所有Table对象产生影响:
metadata = MetaData()
@event.listens_for(metadata, 'column_reflect')
def receive_column_reflect(inspector, table, column_info):
# receives for all Table objects that are reflected
# under this MetaData
# will use the above event hook
my_table = Table("my_table", metadata, autoload_with=some_engine)
新版本 1.4.0b2 中:DDLEvents.column_reflect()钩子现在也可以应用于MetaData对象以及MetaData类本身,它将对与目标MetaData关联的所有Table对象进行操作。
它也可以应用于整个Table类:
from sqlalchemy import Table
@event.listens_for(Table, 'column_reflect')
def receive_column_reflect(inspector, table, column_info):
# receives for all Table objects that are reflected
它还可以应用到使用Table.listeners参数反射的特定Table上:
t1 = Table(
"my_table",
autoload_with=some_engine,
listeners=[
('column_reflect', receive_column_reflect)
]
)
通过方言返回的列信息字典被传递,并且可以被修改。字典是由Inspector.get_columns()返回的列表中的每个元素返回的:
name- 列的名称,应用于Column.name参数。type- 此列的类型,应该是TypeEngine的实例,应用于Column.type参数。nullable- 如果列为 NULL 或 NOT NULL 的布尔标志,应用于Column.nullable参数。default- 列的服务器默认值。通常指定为简单的字符串 SQL 表达式,但事件也可以传递一个FetchedValue、DefaultClause或text()对象。应用于Column.server_default参数。
在对此字典执行任何操作之前调用事件,并且内容可以被修改;以下附加键可以添加到字典中以进一步修改如何构造Column:
key- 将用于在.c集合中访问此Column的字符串键;将应用于Column.key参数。也用于 ORM 映射。请参阅从反射表自动命名列方案章节的示例。quote- 强制或取消对列名进行引用;应用于Column.quote参数。info- 一个任意数据的字典,用于跟踪Column,应用于Column.info参数。
listen() 也接受 propagate=True 修改器以用于此事件;当为 True 时,监听器函数将被建立为目标对象的任何副本,即在使用 Table.to_metadata() 生成的副本。
另请参阅
从反射表自动命名方案 - 在 ORM 映射文档中
拦截列定义 - 在 Automap 文档中
使用数据库无关类型反射 - 在反射数据库对象文档中
attribute dispatch: _Dispatch[_ET] = <sqlalchemy.event.base.DDLEventsDispatch object>
回到 _Dispatch 类的引用。
双向的反对 _Dispatch._events
class sqlalchemy.events.SchemaEventTarget
是DDLEvents事件目标元素的基类。
这包括 SchemaItem 以及 SchemaType。
类签名
类sqlalchemy.events.SchemaEventTarget (sqlalchemy.event.registry.EventTarget)


浙公网安备 33010602011771号