使用引擎和连接¶
本节详细介绍了 Engine
的直接使用,
Connection
和相关对象。重要的是要注意,在使用 SQLAlchemy ORM 时,通常不会访问这些对象;相反,Session
对象用作数据库的接口。但是,对于围绕直接使用文本 SQL 语句和/或 SQL 表达式结构而构建的应用程序,无需 ORM 的更高级别管理服务参与,引擎
和
连接
是国王(和女王?) - 请继续阅读。
基本用法¶
回想一下 Engine Configuration 中,Engine 是通过
create_engine()
调用创建的:
engine = create_engine("mysql+mysqldb://scott:tiger@localhost/test")
create_engine()
的典型用法是每个特定数据库一次
URL,在单个应用程序进程的生命周期内全局保留。单个
Engine
代表 管理许多单独的 DBAPI 连接
进程 和 旨在以并发方式调用。这
Engine
不是 DBAPI connect()
函数的同义词,它只表示一个连接资源 - 在应用程序的模块级别创建一次 Engine
时效率最高,而不是按对象或每个函数调用。
引擎
最基本的功能是提供对
Connection
,然后可以调用 SQL 语句。向数据库发出文本语句如下所示:
from sqlalchemy import text
with engine.connect() as connection:
result = connection.execute(text("select username from users"))
for row in result:
print("username:", row.username)
在上面,Engine.connect()
方法返回一个 Connection
对象,并在 Python 上下文管理器中使用它(例如,使用:
语句)中,Connection.close()
方法会在块的末尾自动调用。Connection
是实际 DBAPI 连接的代理对象。DBAPI 连接是从创建 Connection
时的连接池中检索的。
返回的对象称为 CursorResult
,它引用 DBAPI 游标,并提供用于获取类似于 DBAPI 游标的行的方法。当 DBAPI 游标的所有结果行(如果有)都用完时,CursorResult
将关闭 DBAPI 游标。不返回任何行的 CursorResult
(如 UPDATE 语句的行)(没有任何返回的行))在构造时立即释放游标资源。
当 Connection
在 with:
块的末尾关闭时,引用的 DBAPI 连接将释放到连接池中。从数据库本身的角度来看,假设池有空间存储此连接以供下次使用,则连接池实际上不会“关闭”连接。当连接返回到池中以供重复使用时,池机制会对 DBAPI 连接发出 rollback()
调用,以便
删除任何事务状态或锁定(这称为
Reset On Return),并且该连接已准备好下次使用。
我们上面的示例说明了文本 SQL 字符串的执行,应该使用 text()
结构来调用该字符串,以表明我们想使用文本 SQL。当然,Connection.execute()
方法可以容纳更多内容;请参阅使用数据
在 SQLAlchemy Unified Tutorial 中获取教程。
使用事务¶
注意
本节介绍在直接使用 Engine
和 Connection
对象时如何使用事务。使用
SQLAlchemy ORM 是用于事务控制的公共 API,是通过
Session
对象,它使用 Transaction
object 的有关更多信息,请参阅 管理事务 。
随用随用提交¶
Connection
对象始终发出 SQL 语句
在事务块的上下文中。 第一次使用
调用 Connection.execute()
方法来执行 SQL 语句,则此事务将使用称为 autobegin 的行为自动开始。 该交易在
Connection
对象,直到 Connection.commit()
或 Connection.rollback()
方法。事务结束后,Connection
等待
Connection.execute()
方法,此时它会再次自动启动。
这种调用方式称为 commit as you go,如下例所示:
with engine.connect() as connection:
connection.execute(some_table.insert(), {"x": 7, "y": "this is some data"})
connection.execute(
some_other_table.insert(), {"q": 8, "p": "this is some more data"}
)
connection.commit() # commit the transaction
在 “submit you go” 风格中,我们可以调用 Connection.commit()
和 Connection.rollback()
方法,在使用 Connection.execute()
发出的一系列其他语句中自由;每次结束事务并发出新语句时,新事务都会隐式开始:
with engine.connect() as connection:
connection.execute(text("<some statement>"))
connection.commit() # commits "some statement"
# new transaction starts
connection.execute(text("<some other statement>"))
connection.rollback() # rolls back "some other statement"
# new transaction starts
connection.execute(text("<a third statement>"))
connection.commit() # commits "a third statement"
2.0 版中的新功能:“随用随用”样式是 SQLAlchemy 2.0 的一项新功能。当使用“future”样式引擎时,它也在 SQLAlchemy 1.4 的“transitional”模式下可用。
开始一次¶
Connection
对象提供了一种更明确的事务管理样式,称为 begin once。与 “submit as you go” 相反,“begin once” 允许明确说明事务的起点,并允许事务本身可以作为上下文管理器块构建出来,以便事务的结束是隐式的。要使用 “begin once”,请使用 Connection.begin()
方法,该方法返回一个
Transaction
对象,该对象表示 DBAPI 事务。
此对象还支持通过其自己的
Transaction.commit()
和 Transaction.rollback()
方法,但作为首选做法,还支持上下文管理器界面
where 它将在
该块正常结束,并在引发异常时发出回滚,在
向外传播异常。下面说明了 “begin
once“ 块中:
with engine.connect() as connection:
with connection.begin():
connection.execute(some_table.insert(), {"x": 7, "y": "this is some data"})
connection.execute(
some_other_table.insert(), {"q": 8, "p": "this is some more data"}
)
# transaction is committed
从引擎连接并重新开始一次¶
上述 “begin once” 块的一种方便的简写形式是在原始
Engine
对象,而不是执行 Engine.connect()
和 Connection.begin()
两个单独的步骤;Engine.begin()
方法返回一个特殊的上下文管理器,该管理器在内部维护 Connection
的上下文管理器
以及通常由 Connection.begin()
方法返回的 Transaction
的上下文管理器:
with engine.begin() as connection:
connection.execute(some_table.insert(), {"x": 7, "y": "this is some data"})
connection.execute(
some_other_table.insert(), {"q": 8, "p": "this is some more data"}
)
# transaction is committed, and Connection is released to the connection
# pool
提示
在 Engine.begin()
块中,我们可以调用
Connection.commit()
或 Connection.rollback()
方法,这将结束通常由区块划分的交易
超前。 但是,如果我们这样做,则可能不会有进一步的 SQL作
在 Connection
上发出,直到块结束:
>>> from sqlalchemy import create_engine
>>> e = create_engine("sqlite://", echo=True)
>>> with e.begin() as conn:
... conn.commit()
... conn.begin()
2021-11-08 09:49:07,517 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2021-11-08 09:49:07,517 INFO sqlalchemy.engine.Engine COMMIT
Traceback (most recent call last):
...
sqlalchemy.exc.InvalidRequestError: Can't operate on closed transaction inside
context manager. Please complete the context manager before emitting
further commands.
混合样式¶
“commit as you go”和“begin once”样式可以在单个 Engine.connect()
块中自由混合,前提是对
Connection.begin()
与 “autobegin” 行为不冲突。为此,Connection.begin()
只能在发出任何 SQL 语句之前调用,或者在上一次调用 Connection.commit()
或 Connection.rollback()
之后直接调用:
with engine.connect() as connection:
with connection.begin():
# run statements in a "begin once" block
connection.execute(some_table.insert(), {"x": 7, "y": "this is some data"})
# transaction is committed
# run a new statement outside of a block. The connection
# autobegins
connection.execute(
some_other_table.insert(), {"q": 8, "p": "this is some more data"}
)
# commit explicitly
connection.commit()
# can use a "begin once" block here
with connection.begin():
# run more statements
connection.execute(...)
当开发使用 “begin once” 的代码时,库将引发
InvalidRequestError
如果事务已经 “autobestart” 进行。
设置事务隔离级别,包括 DBAPI 自动提交¶
大多数 DBAPI 都支持可配置事务隔离级别的概念。传统上,这些级别是 “READ UNCOMMITTED”、“READ COMMITTED”、“REPEATABLE READ” 和 “SERIALIZABLE” 四个级别。这些通常在 DBAPI 连接开始新事务之前应用于 DBAPI 连接,请注意,大多数 DBAPI 将在首次发出 SQL 语句时隐式地开始此事务。
支持隔离级别的 DBAPI 通常还支持真正的 “autocommit” 概念,这意味着 DBAPI 连接本身将被置于非事务性自动提交模式。这通常意味着不再发生自动向数据库发出 “BEGIN” 的典型 DBAPI 行为,但它也可能包括其他指令。SQLAlchemy 将“自动提交”的概念视为任何其他隔离级别;因为它是一个隔离级别,不仅失去了 “read committed”,而且也失去了原子性。
提示
请务必注意,这将在下面的部分中进一步讨论
了解 DBAPI 级别的 Autocommit 隔离级别,与任何其他隔离级别一样,“autocommit”隔离级别不会影响 Connection
对象的“事务性”行为,该对象继续调用 DBAPI
.commit()
和 .rollback()
方法(它们在 autocommit 下不起作用),并且 .begin()
方法假定 DBAPI 将隐式启动事务(这意味着 SQLAlchemy 的 “begin” 会
不更改自动提交模式)。
SQLAlchemy 方言应该尽可能地支持这些隔离级别以及自动提交。
为连接设置隔离级别或 DBAPI 自动提交¶
对于从
Engine.connect()
中,可以使用
Connection.execution_options()
方法。该参数称为
Connection.execution_options.isolation_level
值是字符串,通常是以下名称的子集:
# possible values for Connection.execution_options(isolation_level="<value>")
"AUTOCOMMIT"
"READ COMMITTED"
"READ UNCOMMITTED"
"REPEATABLE READ"
"SERIALIZABLE"
并非每个 DBAPI 都支持每个值;如果某个后端使用了 unsupported 的值,则会引发错误。
例如,要在特定连接上强制 REPEATABLE READ,然后开始事务:
with engine.connect().execution_options(
isolation_level="REPEATABLE READ"
) as connection:
with connection.begin():
connection.execute(text("<statement>"))
提示
Connection.execution_options()
该方法的返回值相同
调用
该方法的 Connection 对象,这意味着,它会修改 Connection
的状态
object 就地。 这是 SQLAlchemy 2.0 的新行为。
此行为不适用于 Engine.execution_options()
方法;该方法仍返回 Engine
的副本,如下所述,可用于构建多个 Engine
具有不同执行选项的对象,但它们共享相同的
dialect 和 Connection Pool 的 Dialect 和 Connection Pool。
注意
这 Connection.execution_options.isolation_level
parameter 不一定适用于语句级别的选项,例如
的 Executable.execution_options()
,如果在此级别设置,则将被拒绝。这是因为必须基于每个事务在 DBAPI 连接上设置该选项。
为引擎设置隔离级别或 DBAPI 自动提交¶
该 Connection.execution_options.isolation_level
选项也可以设置为引擎范围,这通常是可取的。这可以通过传递 create_engine.isolation_level
来实现
参数设置为 create_engine()
中:
from sqlalchemy import create_engine
eng = create_engine(
"postgresql://scott:tiger@localhost/test", isolation_level="REPEATABLE READ"
)
使用上述设置,每个新的 DBAPI 连接在创建时都将设置为对所有后续作使用“REPEATABLE READ”
隔离级别设置。
为单个引擎维护多个隔离级别¶
隔离级别也可以按引擎设置,可能更大
级别的灵活性,使用
create_engine.execution_options
参数设置为
create_engine()
或 Engine.execution_options()
方法,后者将创建一个 Engine
副本,该副本共享原始 Engine 的方言和连接池,但具有自己的每个连接隔离级别设置:
from sqlalchemy import create_engine
eng = create_engine(
"postgresql+psycopg2://scott:tiger@localhost/test",
execution_options={"isolation_level": "REPEATABLE READ"},
)
使用上述设置,DBAPI 连接将设置为使用
每个新事务开始的 “REPEATABLE READ”
隔离级别设置;但是,pooled 连接将重置为连接首次发生时存在的原始隔离级别。在 create_engine()
级别,最终效果与使用 create_engine.isolation_level
参数没有任何区别。
但是,经常选择在
不同的隔离级别可能希望创建潜在客户的多个 “子引擎”
Engine
的 API 中,每个 Engine 都将配置为不同的
隔离级别。一个这样的用例是应用程序,其作
分为 “transactional” 和 “read-only”作,一个单独的
使用 “AUTOCOMMIT”
的引擎
可以与主引擎分离:
from sqlalchemy import create_engine
eng = create_engine("postgresql+psycopg2://scott:tiger@localhost/test")
autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT")
在上图中,Engine.execution_options()
方法创建了原始 Engine
的浅表副本。eng
和
autocommit_engine
共享相同的 dialect 和连接池。 但是,
从
autocommit_engine
。
当连接返回到连接池时,无论隔离级别设置是哪一个,都会无条件地恢复。
另请参阅
设置 Transaction Isolation Levels / DBAPI AUTOCOMMIT - 用于 ORM
使用 DBAPI 自动提交允许透明重新连接的只读版本 - 一种使用 DBAPI 自动提交以透明方式重新连接到数据库以进行只读作的配方
了解 DBAPI 级别的 autocommit 隔离级别¶
在父部分中,我们介绍了
Connection.execution_options.isolation_level
参数以及如何使用它来设置数据库隔离级别,包括
DBAPI 级别的“自动提交”,SQLAlchemy 将其视为另一个事务
隔离级别。 在本节中,我们将尝试阐明其含义
这种方法。
如果我们想签出一个 Connection
对象并使用它的 “autocommit” 模式,我们将按如下方式进行:
with engine.connect() as connection:
connection.execution_options(isolation_level="AUTOCOMMIT")
connection.execute(text("<statement>"))
connection.execute(text("<statement>"))
上面说明了 “DBAPI autocommit” 模式的正常用法。无需使用 Connection.begin()
等方法
或 Connection.commit(),
因为所有语句都会立即提交到数据库。当块结束时,Connection
对象将恢复 “autocommit” 隔离级别,并且 DBAPI 连接
被释放到连接池中,其中 DBAPI connection.rollback()
方法,但由于上述语句已经
committed,则此回滚不会更改数据库的状态。
请务必注意,即使调用 Connection.begin()
方法,“autocommit” 模式也会持续存在;DBAPI 不会向数据库发出任何 BEGIN,也不会在调用 Connection.commit()
时发出 COMMIT。这种用法也不是错误场景,因为预计 “autocommit” 隔离级别可能会应用于假设事务上下文编写的代码;毕竟,“隔离级别”是事务本身的配置细节,就像任何其他隔离级别一样。
在下面的示例中,语句保持不变
autocommitting 而不管 SQLAlchemy 级别的事务块如何:
with engine.connect() as connection:
connection = connection.execution_options(isolation_level="AUTOCOMMIT")
# this begin() does not affect the DBAPI connection, isolation stays at AUTOCOMMIT
with connection.begin() as trans:
connection.execute(text("<statement>"))
connection.execute(text("<statement>"))
当我们在打开日志记录的情况下运行像上面这样的块时,日志记录将尝试表明,当调用 DBAPI 级别的 .commit()
时,由于自动提交模式,它可能没有效果:
INFO sqlalchemy.engine.Engine BEGIN (implicit)
...
INFO sqlalchemy.engine.Engine COMMIT using DBAPI connection.commit(), DBAPI should ignore due to autocommit mode
同时,即使我们使用的是“DBAPI autocommit”,SQLAlchemy 的事务语义,即 Connection.begin()
的 Python 内行为
以及 “autobegin” 的行为,即使这些
不会影响 DBAPI 连接本身。为了说明这一点,下面的代码将引发一个错误,因为 Connection.begin()
是在 autobegin 发生后被调用的:
with engine.connect() as connection:
connection = connection.execution_options(isolation_level="AUTOCOMMIT")
# "transaction" is autobegin (but has no effect due to autocommit)
connection.execute(text("<statement>"))
# this will raise; "transaction" is already begun
with connection.begin() as trans:
connection.execute(text("<statement>"))
上面的示例还演示了与 “autocommit” 相同的主题
隔离级别是底层数据库的配置详细信息
transaction 的 API,并且独立于 SQLAlchemy 的 begin/commit 行为
Connection 对象。“autocommit” 模式不会与
Connection.begin()
和 Connection
在执行自己的状态更改时不查阅此状态
添加到事务中(除了在 Engine Logging 中建议
这些块实际上并没有提交)。这种设计的基本原理是
与
可以独立更改 DBAPI 自动提交模式而不指示其他位置的任何代码更改的连接。
在隔离级别之间更改¶
隔离级别设置(包括自动提交模式)会自动重置
当连接被释放回连接池时。因此它是
最好避免尝试在单个
connection
对象,因为这会导致过多的冗长。
为了说明如何在单个 Connection
签出的范围内以 ad hoc 模式使用 “autocommit”,
Connection.execution_options.isolation_level
参数必须重新应用之前的隔离级别。上一节演示了调用 Connection.begin()
的尝试
为了在 autocommit 发生时启动事务;我们可以
重写该示例以实际执行此作,方法是首先恢复隔离级别
在我们调用 Connection.begin()
之前:
# if we wanted to flip autocommit on and off on a single connection/
# which... we usually don't.
with engine.connect() as connection:
connection.execution_options(isolation_level="AUTOCOMMIT")
# run statement(s) in autocommit mode
connection.execute(text("<statement>"))
# "commit" the autobegun "transaction"
connection.commit()
# switch to default isolation level
connection.execution_options(isolation_level=connection.default_isolation_level)
# use a begin block
with connection.begin() as trans:
connection.execute(text("<statement>"))
在上面,要手动恢复我们使用的隔离级别
Connection.default_isolation_level
恢复默认值
isolation level (假设这就是我们这里想要的)。然而,它是
使用
已在
签入时自动重置隔离级别的连接。编写上述内容的首选方法是使用两个块
# use an autocommit block
with engine.connect().execution_options(isolation_level="AUTOCOMMIT") as connection:
# run statement in autocommit mode
connection.execute(text("<statement>"))
# use a regular block
with engine.begin() as connection:
connection.execute(text("<statement>"))
总结一下:
“DBAPI 级别自动提交”隔离级别完全独立于Connection
对象的 “begin” 和 “commit” 概念
对每个隔离级别使用单独的Connection
检出。避免在单个连接检出时尝试在 “autocommit” 之间来回切换;让引擎执行恢复默认隔离级别的工作
使用服务器端游标 (又名流结果)¶
某些后端明确支持“服务器端游标”与“客户端游标”的概念。这里的客户端游标意味着数据库驱动程序在从语句执行返回之前,将结果集中的所有行完全提取到内存中。默认情况下,PostgreSQL 和 MySQL/MariaDB 的驱动程序等驱动程序通常使用客户端游标。相比之下,服务器端游标指示结果行在数据库服务器的状态中保持挂起状态,因为结果行被客户端使用。例如,Oracle Database 的驱动程序通常使用“服务器端”模型,而 SQLite 方言虽然没有使用真正的“客户端/服务器”架构,但仍然使用无缓冲的结果获取方法,该方法会在结果行被使用之前将结果行留在进程内存之外。
从这个基本架构可以看出,当获取非常大的结果集时,“服务器端游标”的内存效率更高,但同时可能会给客户端/服务器通信过程带来更多的复杂性,并且对于较小的结果集(通常少于 10000 行)来说效率较低。
对于那些有条件地支持缓冲或无缓冲结果的方言,通常对使用“无缓冲”或服务器端光标模式有警告。例如,当使用 psycopg2 方言时,如果服务器端游标与任何类型的 DML 或 DDL 语句一起使用,则会引发错误。将 MySQL 驱动程序与服务器端游标一起使用时,DBAPI 连接处于更脆弱的状态,并且不会从错误情况中正常恢复,也不允许继续回滚,直到游标完全关闭。
因此,SQLAlchemy 的方言将始终默认为不太容易出错的游标版本,这意味着对于 PostgreSQL 和 MySQL 方言,它默认为缓冲的“客户端”游标,在从游标调用任何 fetch 方法之前,将全部结果提取到内存中。这种作模式适用于绝大多数情况;无缓冲游标通常没有用,除非应用程序以块形式获取大量行,在这种情况下,这些行的处理可以在获取更多行之前完成。
对于提供客户端和服务器端游标选项的数据库驱动程序, Connection.execution_options.stream_results
和 Connection.execution_options.yield_per
执行选项提供对每个 Connection
上的“服务器端游标”的访问
或按语句计算。 使用 ORM 时也存在类似的选项
会话
。
通过 yield_per 使用固定缓冲区进行流式处理¶
作为具有完全无缓冲服务器端游标的单个行获取作
通常比一次获取批量行更昂贵,因此
Connection.execution_options.yield_per
execution 选项配置一个 Connection
或语句以使用
服务器端游标可用,同时配置
固定大小的行缓冲区,这些行将从服务器批量检索行,如
他们被消耗掉了。此参数可以是正整数值,使用
Connection.execution_options()
method 开启
Connection
或语句上使用
Executable.execution_options()
方法。
1.4.40 版本中的新功能: Connection.execution_options.yield_per
作为仅核心选项是 SQLAlchemy 1.4.40 的新增功能;对于之前的 1.4 版本,请使用 Connection.execution_options.stream_results
直接与 Result.yield_per()
组合使用。
使用此选项等效于手动设置
Connection.execution_options.stream_results
选择
,然后调用
Result.yield_per()
方法
对象。 在这两种情况下,this 的效果
组合包括:
为给定后端选择了 Server Side Cursors 模式(如果可用,但尚未成为该后端的默认行为)
当 Result 行被获取时,它们将被批量缓冲,其中 直到最后一个批次的每个批次的大小将等于整数 参数传递给Connection.execution_options.yield_per
选项或Result.yield_per()
方法;然后,根据小于此大小的剩余行调整最后一个批次的大小Result.partitions()
使用的默认分区大小 method(如果使用)也将等于此整数大小。
以下示例说明了这三种行为:
with engine.connect() as conn:
with conn.execution_options(yield_per=100).execute(
text("select * from table")
) as result:
for partition in result.partitions():
# partition is an iterable that will be at most 100 items
for row in partition:
print(f"{row}")
上面的示例说明了 yield_per=100
的组合以及使用 Result.partitions()
方法对与从服务器获取的大小匹配的批量行运行处理。Result.partitions()
的使用是可选的,如果
Result
直接迭代,则新一批行将是
buffered 的 100 行。 调用
不应使用 Result.all(),
因为这将一次完全获取所有剩余行,并违背使用 yield_per
的目的。
该 Connection.execution_options.yield_per
选项也可以移植到 ORM 中,Session 使用它来获取 ORM 对象,它还限制了一次生成的 ORM 对象的数量。请参阅 ORM Querying Guide 中的 Fetching large result sets with Yield Per - 部分
有关使用
Connection.execution_options.yield_per
与 ORM 一起。
1.4.40 版本中的新功能: 添加
Connection.execution_options.yield_per
作为 Core 级别的执行选项来方便地设置流式结果,
缓冲区大小和分区大小以可传输的方式同时进行
到 ORM 的类似用例。
使用 stream_results 使用动态增长的缓冲区进行流式处理¶
要启用没有特定分区大小的服务器端游标,
Connection.execution_options.stream_results
选项,就像在 Connection
对象或 statement 对象上调用一样 Connection.execution_options.yield_per
。
当使用
Connection.execution_options.stream_results
选择
直接迭代,则在内部获取行
使用默认缓冲方案,首先缓冲一小群行,
然后在每次提取时增加一个越来越大的缓冲区,直到达到预配置的限制
的 1000 行。 此缓冲区的最大大小可以使用
Connection.execution_options.max_row_buffer
执行选项:
with engine.connect() as conn:
with conn.execution_options(stream_results=True, max_row_buffer=100).execute(
text("select * from table")
) as result:
for row in result:
print(f"{row}")
Connection.execution_options.stream_results
虽然
选项可以与 Result.partitions()
结合使用
方法,则应将特定的分区大小传递给
Result.partitions() 的 Result.partitions()
方法,以便不会获取整个结果。
使用
Connection.execution_options.yield_per
选项。
Schema 名称的翻译¶
支持分发公共表集的多租户应用程序
添加到多个 schema 中,
Connection.execution_options.schema_translate_map
execution 选项可用于重新调整一组 Table
对象的用途,以便在不同的 schema 名称下呈现,而无需进行任何更改。
给定一个表:
user_table = Table(
"user",
metadata_obj,
Column("id", Integer, primary_key=True),
Column("name", String(50)),
)
此 Table
的 “schema” 由
Table.schema
属性为 None
。 这
Connection.execution_options.schema_translate_map
可以指定所有 schema
为 None
的 Table 对象都将 schema 渲染为 user_schema_one
:
connection = engine.connect().execution_options(
schema_translate_map={None: "user_schema_one"}
)
result = connection.execute(user_table.select())
上面的代码将在以下形式的数据库上调用 SQL:
SELECT user_schema_one.user.id, user_schema_one.user.name FROM
user_schema_one.user
也就是说,架构名称将替换为我们翻译后的名称。该映射可以指定任意数量的 target->destination 架构:
connection = engine.connect().execution_options(
schema_translate_map={
None: "user_schema_one", # no schema name -> "user_schema_one"
"special": "special_schema", # schema="special" becomes "special_schema"
"public": None, # Table objects with schema="public" will render with no schema
}
)
该 Connection.execution_options.schema_translate_map
参数会影响从 SQL 表达式语言生成的所有 DDL 和 SQL 构造,这些构造派生自 Table
或 Sequence
对象。它不会影响通过 text()
使用的文本字符串 SQL
construct 或通过传递给 Connection.execute()
的纯字符串。
该功能仅在架构名称直接派生自 Table
或 Sequence
的名称的情况下生效;它不会影响直接传递字符串架构名称的方法。通过这种模式,它在 MetaData.create_all() 或
MetaData.drop_all()
调用,并在给定 Table
对象的情况下使用表反射时生效。 然而,它确实如此
不会影响 Inspector
对象上的作,因为架构名称会显式传递给这些方法。
提示
要将架构转换功能与 ORM 会话
一起使用,请在 Engine
级别设置此选项,然后将该引擎传递给 Session
。Session
使用新的
每笔交易的连接
:
schema_engine = engine.execution_options(schema_translate_map={...})
session = Session(schema_engine)
...
警告
当使用不带扩展的 ORM Session
时,架构
translate 功能仅支持作为
每个 Session 一个 schema 转换映射。如果基于每个语句给出不同的模式转换映射,它将不起作用,因为 ORM 会话
不会将当前模式转换值考虑到单个对象。
将单个 Session
与多个 schema_translate_map
一起使用
配置,则可以使用 Horizontal Sharding 扩展。请参阅 水平分片 中的示例。
SQL 编译缓存¶
1.4 版本中的新功能: SQLAlchemy 现在有一个透明的查询缓存系统,大大降低了跨 Core 和 ORM 将 SQL 语句构造转换为 SQL 字符串所涉及的 Python 计算开销。请参阅添加到所有 DQL 的透明 SQL 编译缓存、核心中的 DML 语句、ORM 中的介绍。
SQLAlchemy 还包括一个用于 SQL 编译器的综合缓存系统
作为其 ORM 变体。 此缓存系统在
Engine
并规定给定 Core 或 ORM SQL 语句的 SQL 编译过程,以及为该语句组装结果获取机制的相关计算,对于该语句对象和具有相同结构的所有其他对象,在特定结构保留在引擎的“编译缓存”中的持续时间内,将仅发生一次。通过“具有相同结构的语句对象”,这通常对应于在函数中构造的 SQL 语句,并且每次该函数运行时都会生成:
def run_my_statement(connection, parameter):
stmt = select(table)
stmt = stmt.where(table.c.col == parameter)
stmt = stmt.order_by(table.c.id)
return connection.execute(stmt)
上述语句将生成类似于
SELECT id, col FROM table WHERE col = :col ORDER BY id
,请注意,虽然 parameter
的值是普通的 Python 对象,例如字符串
或整数,则语句的字符串 SQL 形式不包含此
值,因为它使用绑定参数。 上述内容的后续调用
run_my_statement()
函数将使用 connection.execute()
调用范围内的缓存编译结构以提高性能。
注意
请务必注意,SQL 编译缓存仅缓存传递给数据库的 SQL 字符串,而不是数据
由 query 返回。 它绝不是数据缓存,也不会
影响特定 SQL 语句返回的结果,也不会影响
暗示与获取结果行相关的任何内存使用。
虽然 SQLAlchemy 从 1.x 系列早期开始就有一个基本的语句缓存,并且还为 ORM 提供了“Baked Query”扩展,但这两个系统都需要高度的特殊 API 使用才能使缓存有效。相反,从 1.4 开始的新缓存是完全自动的,不需要改变编程风格即可生效。
缓存会自动使用,无需任何配置更改,也无需特殊步骤即可启用它。以下部分详细介绍了缓存的配置和高级使用模式。
配置¶
缓存本身是一个类似字典的对象,称为 LRUCache
,它是
一个内部 SQLAlchemy 字典子类,用于跟踪特定
键,并具有定期的“修剪”步骤,该步骤会删除最近的
当缓存大小达到特定阈值时,已使用项目。 尺寸
的 500 个缓存,可以使用
create_engine.query_cache_size
参数:
engine = create_engine(
"postgresql+psycopg2://scott:tiger@localhost/test", query_cache_size=1200
)
缓存的大小可以增长到给定大小的 150% 的倍数,然后再修剪回目标大小。因此,大小为 1200 以上的缓存可以增长到 1800 个元素,此时它将被修剪到 1200 个元素。
缓存的大小调整基于每个引擎呈现的每个唯一 SQL 语句的单个条目。从 Core 和 ORM 生成的 SQL 语句被同等对待。DDL 语句通常不会被缓存。为了确定缓存正在做什么,引擎日志记录将包含有关缓存行为的详细信息,如下一节所述。
使用 Logging 估算缓存性能¶
上述缓存大小 1200 实际上相当大。 对于小型应用,
大小 100 可能就足够了。 要估计缓存的最佳大小,
假设目标主机上存在足够的内存,则缓存的大小
应基于可为
目标引擎正在使用中。 实现这一点的最权宜之计是使用
SQL 回显,最直接地通过使用
create_engine.echo
标志,或使用 Python 日志记录;有关日志记录配置的背景信息,请参阅 配置日志记录 部分。
例如,我们将检查以下程序生成的日志记录:
from sqlalchemy import Column
from sqlalchemy import create_engine
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import select
from sqlalchemy import String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Session
Base = declarative_base()
class A(Base):
__tablename__ = "a"
id = Column(Integer, primary_key=True)
data = Column(String)
bs = relationship("B")
class B(Base):
__tablename__ = "b"
id = Column(Integer, primary_key=True)
a_id = Column(ForeignKey("a.id"))
data = Column(String)
e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
s = Session(e)
s.add_all([A(bs=[B(), B(), B()]), A(bs=[B(), B(), B()]), A(bs=[B(), B(), B()])])
s.commit()
for a_rec in s.scalars(select(A)):
print(a_rec.bs)
运行时,记录的每个 SQL 语句都将在传递的参数左侧包含一个带括号的缓存统计信息徽章。我们可能看到的四种类型的消息总结如下:
[原始 SQL]
- 驱动程序或最终用户使用Connection.exec_driver_sql()
- 缓存不适用[no key]
- 语句对象是未缓存的 DDL 语句,或者语句对象包含不可缓存的元素,例如用户定义的构造或任意大的 VALUES 子句。[在 Xs 中生成]
- 该语句是缓存未命中,必须编译,然后存储在缓存中。生成编译后的构造需要 X 秒。数字 X 将位于小数秒内。[cached since Xs ago]
- 该语句是缓存命中,不必重新编译。该语句自 X 秒前以来一直存储在缓存中。数字 X 将与应用程序运行的时间和语句的缓存时间成正比,例如,在 24 小时内为 86400。
下面将更详细地介绍每个徽章。
我们看到的上述程序的第一个语句将是 SQLite 方言检查是否存在 “a” 和 “b” 表:
INFO sqlalchemy.engine.Engine PRAGMA temp.table_info("a")
INFO sqlalchemy.engine.Engine [raw sql] ()
INFO sqlalchemy.engine.Engine PRAGMA main.table_info("b")
INFO sqlalchemy.engine.Engine [raw sql] ()
对于上述两个 SQLite PRAGMA 语句,徽章显示为 [raw sql]
,这表示驱动程序正在使用 Connection.exec_driver_sql()
将 Python 字符串直接发送到数据库。缓存不适用于此类语句,因为它们已经以字符串形式存在,并且由于SQLAlchemy不会提前解析SQL字符串,因此不知道将返回哪种结果行。
我们看到的下一个语句是 CREATE TABLE 语句:
INFO sqlalchemy.engine.Engine
CREATE TABLE a (
id INTEGER NOT NULL,
data VARCHAR,
PRIMARY KEY (id)
)
INFO sqlalchemy.engine.Engine [no key 0.00007s] ()
INFO sqlalchemy.engine.Engine
CREATE TABLE b (
id INTEGER NOT NULL,
a_id INTEGER,
data VARCHAR,
PRIMARY KEY (id),
FOREIGN KEY(a_id) REFERENCES a (id)
)
INFO sqlalchemy.engine.Engine [no key 0.00006s] ()
对于这些语句中的每一个,徽章上都显示为 [no key 0.00006s]。
这表明这两个特定语句没有发生缓存,因为面向 DDL 的 CreateTable
构造没有生成缓存键。DDL 结构通常不参与缓存,因为它们通常不会重复第二次,并且 DDL 也是一个数据库配置步骤,其中性能不那么重要。
[no key]
徽章很重要,还有另一个原因,因为它可以为可缓存的 SQL 语句生成,但当前不可缓存的某些特定子结构除外。这方面的示例包括不定义缓存参数的自定义用户定义的 SQL 元素,以及一些生成任意长度且不可重现的 SQL 字符串的构造,主要示例是 Values
构造以及将“多值插入”与 Insert.values()
方法一起使用时。
到目前为止,我们的缓存仍然是空的。接下来的语句将被缓存,但是,一个 segment 如下所示:
INFO sqlalchemy.engine.Engine INSERT INTO a (data) VALUES (?)
INFO sqlalchemy.engine.Engine [generated in 0.00011s] (None,)
INFO sqlalchemy.engine.Engine INSERT INTO a (data) VALUES (?)
INFO sqlalchemy.engine.Engine [cached since 0.0003533s ago] (None,)
INFO sqlalchemy.engine.Engine INSERT INTO a (data) VALUES (?)
INFO sqlalchemy.engine.Engine [cached since 0.0005326s ago] (None,)
INFO sqlalchemy.engine.Engine INSERT INTO b (a_id, data) VALUES (?, ?)
INFO sqlalchemy.engine.Engine [generated in 0.00010s] (1, None)
INFO sqlalchemy.engine.Engine INSERT INTO b (a_id, data) VALUES (?, ?)
INFO sqlalchemy.engine.Engine [cached since 0.0003232s ago] (1, None)
INFO sqlalchemy.engine.Engine INSERT INTO b (a_id, data) VALUES (?, ?)
INFO sqlalchemy.engine.Engine [cached since 0.0004887s ago] (1, None)
在上面,我们基本上看到了两个唯一的 SQL 字符串; "INSERT INTO a (data) VALUES (?)"
和 "INSERT INTO b (a_id, data) VALUES (?, ?)"
.由于 SQLAlchemy 对所有 Literal 值使用绑定参数,因此即使这些语句针对不同的对象重复多次,但由于参数是独立的,因此实际的 SQL 字符串保持不变。
注意
以上两个语句是由 ORM 工作单元进程生成的,实际上会将它们缓存在每个 Mapper 本地的单独缓存中。但是,机制和术语是相同的。下面的禁用或使用备用字典缓存某些(或全部)语句部分将介绍面向用户的代码如何也可以基于每个语句使用备用缓存容器。
我们看到的这两个语句第一次出现的缓存徽章是 [generate in 0.00011s]。
这表示该语句不在缓存中,在 .00011 中被编译成 String,然后
cached 的 Cached 中。当我们看到 [generated]
徽章时,我们知道这意味着缓存未命中。对于特定语句的第一次出现,这是预期的。但是,如果大量新的 [生成]
徽章
对于通常使用相同序列的长时间运行的应用程序进行观察
SQL 语句中,这可能表明
create_engine.query_cache_size
参数太小。当缓存的语句由于 LRU 缓存修剪较少使用的项而被从缓存中逐出时,它将在下次使用时显示 [generated]
徽章。
然后,我们看到这两个语句的后续出现的缓存徽章类似于 [cached since 0.0003533s ago]。
这表示该语句是在缓存中找到的,并且最初是
放入缓存中 .0003533 秒。请务必注意,虽然 [generated]
和 [cached since]
徽章指的是秒数,但它们的含义不同;对于 [generated]
,该数字是编译 statement 所花费时间的粗略时间,并且将是极小的时间。对于 [cached since]
,这是语句存在于缓存中的总时间。对于已运行 6 小时的应用程序,此数字可能会读取 [cached
since 21600 seconds ago]
,这是一件好事。 看到 的高数字
“cached since” 表示这些语句未受
缓存未命中。 通常具有少量
“cached since” 即使应用程序已运行很长时间,也可能
表示这些语句太频繁地受到缓存未命中的影响,并且
这
create_engine.query_cache_size
可能需要增加。
然后,我们的示例程序执行一些 SELECT,对于“a”表的 SELECT 以及“b”表的后续延迟加载,我们可以看到相同的 “generated” 然后 “cached” 模式:
INFO sqlalchemy.engine.Engine SELECT a.id AS a_id, a.data AS a_data
FROM a
INFO sqlalchemy.engine.Engine [generated in 0.00009s] ()
INFO sqlalchemy.engine.Engine SELECT b.id AS b_id, b.a_id AS b_a_id, b.data AS b_data
FROM b
WHERE ? = b.a_id
INFO sqlalchemy.engine.Engine [generated in 0.00010s] (1,)
INFO sqlalchemy.engine.Engine SELECT b.id AS b_id, b.a_id AS b_a_id, b.data AS b_data
FROM b
WHERE ? = b.a_id
INFO sqlalchemy.engine.Engine [cached since 0.0005922s ago] (2,)
INFO sqlalchemy.engine.Engine SELECT b.id AS b_id, b.a_id AS b_a_id, b.data AS b_data
FROM b
WHERE ? = b.a_id
从我们上面的程序中,完整运行显示总共缓存了四个不同的 SQL 字符串。这表明缓存大小为 4 就足够了。这显然是一个非常小的大小,默认大小 500 可以保留为默认值。
缓存使用多少内存?¶
上一节详细介绍了一些技术来检查
create_engine.query_cache_size
需要更大。 我们如何知道
如果缓存不是太大? 我们可能想要设置
create_engine.query_cache_size
不高于某个数字是因为我们的应用程序可能会使用大量不同的语句,例如从搜索 UX 动态构建查询的应用程序,并且我们不希望我们的主机耗尽内存,例如, 在过去 24 小时内运行了 10 万个不同的查询,并且这些查询都被缓存了。
测量 Python 数据结构占用了多少内存是极其困难的,但是当连续的 250 个新语句添加到缓存中时,使用一个过程通过 top
来测量内存的增长,这表明一个中等的 Core 语句占用大约 12K,而一个小的 ORM 语句占用大约 20K, 包括 ORM 的 result-fetching 结构,这将要大得多。
禁用或使用备用字典缓存一些(或全部)语句¶
使用的内部缓存称为 LRUCache
,但这主要只是一个字典。任何字典都可以用作任何系列语句的缓存,方法是使用 Connection.execution_options.compiled_cache
选项作为执行选项。 可以在语句上设置执行选项,
在 Engine
或 Connection
上,以及使用 ORM Session.execute()
方法进行 SQLAlchemy-2.0 样式调用时。例如,要运行一系列 SQL 语句并将它们缓存在特定字典中:
my_cache = {}
with engine.connect().execution_options(compiled_cache=my_cache) as conn:
conn.execute(table.select())
SQLAlchemy ORM 使用上述技术来保留工作单元“刷新”进程中的每个映射器缓存,这些缓存与 Engine
上配置的默认缓存以及某些关系加载器查询分开。
也可以使用此参数禁用缓存,方法是发送
无
:
# disable caching for this connection
with engine.connect().execution_options(compiled_cache=None) as conn:
conn.execute(table.select())
第三方方言的缓存¶
缓存功能要求 dialect 的编译器生成 SQL 字符串,这些字符串可以安全地用于许多语句调用,前提是具有与该 SQL 字符串相关的特定缓存键。这意味着语句中的任何 Literals 值(例如 SELECT 的 LIMIT/OFFSET 值)都不能在方言的编译方案中进行硬编码,因为编译后的字符串将不可重用。SQLAlchemy 支持使用 BindParameter.render_literal_execute()
方法可以应用于现有Select._limit_clause
和
Select._offset_clause
属性,本节稍后将对此进行说明。
由于有许多第三方方言,其中许多方言可能从 SQL 语句生成文字值,而没有较新的“文字执行”功能的好处,因此 SQLAlchemy 从 1.4.5 版开始向方言添加了一个称为 Dialect.supports_statement_cache
.此属性为
在运行时检查它是否存在于特定 dialect 的类中,
即使它已经存在于超类上,因此即使是第三方
dialect 中,该 dialect 子类化现有的可缓存 SQLAlchemy dialect,例如
sqlalchemy.dialects.postgresql.PGDialect
仍必须显式包含此属性才能启用缓存。只有在根据需要更改了方言并测试了具有不同参数的已编译 SQL 语句的可重用性后,才应启用该属性。
对于所有不支持此属性的第三方方言,此类方言的日志记录将指示 dialect does not support caching
.
当 dialect 经过缓存测试后,特别是 SQL 编译器已更新为不直接在 SQL 字符串中呈现任何文字 LIMIT / OFFSET,dialect 作者可以按如下方式应用该属性:
from sqlalchemy.engine.default import DefaultDialect
class MyDialect(DefaultDialect):
supports_statement_cache = True
该标志也需要应用于方言的所有子类:
class MyDBAPIForMyDialect(MyDialect):
supports_statement_cache = True
1.4.5 版本中的新功能: 添加了 Dialect.supports_statement_cache
属性。
方言修改的典型情况如下。
示例:使用后编译参数渲染 LIMIT / OFFSET¶
例如,假设一个方言覆盖了 SQLCompiler.limit_clause()
方法,该方法为 SQL 语句生成 “LIMIT / OFFSET” 子句,
喜欢这个:
# pre 1.4 style code
def limit_clause(self, select, **kw):
text = ""
if select._limit is not None:
text += " \n LIMIT %d" % (select._limit,)
if select._offset is not None:
text += " \n OFFSET %d" % (select._offset,)
return text
上述例程将 Select._limit
和
Select._offset
整数值作为嵌入在 SQL 语句中的文字整数。对于不支持在 SELECT 语句的 LIMIT/OFFSET 子句中使用绑定参数的数据库,这是一个常见的要求。但是,在初始编译阶段渲染整数值与缓存直接不兼容,因为 Select
对象的 limit 和 offset 整数值不是缓存键的一部分,因此许多
具有不同
limit/offset 值的 select 语句不会以正确的值呈现。
对上述代码的更正是将文本整数移动到 SQLAlchemy 的后编译工具中,该工具将在初始编译阶段之外呈现文本整数,而是在将语句发送到 DBAPI 之前的执行时呈现。这可以在编译阶段使用 BindParameter.render_literal_execute()
方法结合使用 Select._limit_clause
和
Select._offset_clause
属性,这些属性将 LIMIT/OFFSET 表示为完整的 SQL 表达式,如下所示:
# 1.4 cache-compatible code
def limit_clause(self, select, **kw):
text = ""
limit_clause = select._limit_clause
offset_clause = select._offset_clause
if select._simple_int_clause(limit_clause):
text += " \n LIMIT %s" % (
self.process(limit_clause.render_literal_execute(), **kw)
)
elif limit_clause is not None:
# assuming the DB doesn't support SQL expressions for LIMIT.
# Otherwise render here normally
raise exc.CompileError(
"dialect 'mydialect' can only render simple integers for LIMIT"
)
if select._simple_int_clause(offset_clause):
text += " \n OFFSET %s" % (
self.process(offset_clause.render_literal_execute(), **kw)
)
elif offset_clause is not None:
# assuming the DB doesn't support SQL expressions for OFFSET.
# Otherwise render here normally
raise exc.CompileError(
"dialect 'mydialect' can only render simple integers for OFFSET"
)
return text
上面的方法将生成一个编译后的 SELECT 语句,如下所示:
SELECT x FROM y
LIMIT __[POSTCOMPILE_param_1]
OFFSET __[POSTCOMPILE_param_2]
在上面,__[POSTCOMPILE_param_1]
和 __[POSTCOMPILE_param_2]
indicators 将在
语句执行时间,从
缓存。
在进行上述适当更改后,
Dialect.supports_statement_cache
flag 应设置为 True
。
强烈建议第三方方言使用
Dialect 第三方测试套件
这将断言像
带有 LIMIT/OFFSET 的 SELECT 将正确呈现和缓存。
使用 Lambda 显著提高语句生成速度¶
深度炼金术
除非在性能非常密集的场景中,否则此技术通常不是必需的,并且适用于经验丰富的 Python 程序员。虽然相当简单,但它涉及的元编程概念并不适合 Python 开发人员新手。lambda 方法可以在以后以最少的工作量应用于现有代码。
Python 函数(通常表示为 lambda)可用于生成 SQL 表达式,这些表达式可根据 lambda 函数本身的 Python 代码位置以及 lambda 中的闭包变量进行缓存。其基本原理是,不仅允许缓存 SQL 表达式构造的 SQL 字符串编译形式(当不使用 lambda 系统时 SQLAlchemy 的正常行为),还允许缓存 SQL 表达式构造本身的 Python 内部组合,这也具有一定程度的 Python 开销。
lambda SQL 表达式功能作为性能增强功能提供,也可以选择在 with_loader_criteria()
中使用
ORM 选项来提供通用的 SQL 片段。
剧情简介¶
Lambda 语句是使用 lambda_stmt()
函数构建的,该函数返回 StatementLambdaElement
的实例,该实例本身就是一个可执行语句构造。使用 Python 加法运算符 +
或允许更多选项 StatementLambdaElement.add_criteria()
的方法将其他修饰符和条件添加到对象中。
假设 lambda_stmt()
结构是在期望在应用程序中多次使用的封闭函数或方法中调用的,以便第一次执行之后的后续执行可以利用缓存的已编译 SQL。当 lambda 在 Python 的封闭函数内部构造时,它还会受到闭包变量的影响,这对整个方法很重要:
from sqlalchemy import lambda_stmt
def run_my_statement(connection, parameter):
stmt = lambda_stmt(lambda: select(table))
stmt += lambda s: s.where(table.c.col == parameter)
stmt += lambda s: s.order_by(table.c.id)
return connection.execute(stmt)
with engine.connect() as conn:
result = run_my_statement(some_connection, "some parameter")
在上图中,用于定义 SELECT 语句结构的三个 lambda
可调用对象只调用一次,生成的 SQL 字符串缓存在引擎的编译缓存中。从那时起,run_my_statement()
函数可以被调用任意次数,其中的 lambda
可调用对象将不会被调用,仅用作缓存键来检索已编译的 SQL。
注意
请务必注意,当不使用 lambda 系统时,已经存在 SQL 缓存。lambda 系统仅通过缓存 SQL 结构本身的构建并使用更简单的缓存键来为每个调用的 SQL 语句增加一个额外的工作减少层。
Lambda 的快速指南¶
最重要的是,lambda SQL 系统的重点是确保为 lambda 生成的缓存键与其生成的 SQL 字符串之间永远不会不匹配。LambdaElement
和相关对象将运行并分析给定的 lambda,以计算每次运行时应如何缓存它,并尝试检测任何潜在问题。基本准则包括:
支持任何类型的语句 - 虽然预期select()
结构是lambda_stmt()
的主要用例,DML 语句(如insert()
和update()
)同样可用:def upd(id_, newname): stmt = lambda_stmt(lambda: users.update()) stmt += lambda s: s.values(name=newname) stmt += lambda s: s.where(users.c.id == id_) return stmt with engine.begin() as conn: conn.execute(upd(7, "foo"))
也直接支持 ORM 用例 -lambda_stmt()
可以完全容纳 ORM 功能并直接与Session.execute()
中:def select_user(session, name): stmt = lambda_stmt(lambda: select(User)) stmt += lambda s: s.where(User.name == name) row = session.execute(stmt).first() return row
自动容纳绑定参数 - 与 SQLAlchemy 之前的“烘焙查询”系统相比,lambda SQL 系统容纳 Python 文字值,这些值会自动成为 SQL 绑定参数。这意味着,即使给定的 lambda 只运行一次,也会在每次运行时从 lambda 的闭包中提取成为绑定参数的值:>>> def my_stmt(x, y): ... stmt = lambda_stmt(lambda: select(func.max(x, y))) ... return stmt >>> engine = create_engine("sqlite://", echo=True) >>> with engine.connect() as conn: ... print(conn.scalar(my_stmt(5, 10))) ... print(conn.scalar(my_stmt(12, 8)))
SELECT max(?, ?) AS max_1 [generated in 0.00057s] (5, 10)10SELECT max(?, ?) AS max_1 [cached since 0.002059s ago] (12, 8)12
在上面,StatementLambdaElement
提取了x
的值y
来自每次生成的 lambda 的闭包调用 my_stmt();
这些参数被替换为缓存的 SQL 结构中作为参数的值。
理想情况下,lambda 应在所有情况下生成相同的 SQL 结构 - 避免在 lambda 中使用条件或自定义可调用对象,这可能会使其根据输入生成不同的 SQL;如果函数可能有条件地使用两个不同的 SQL 片段,请使用两个单独的 lambda:# **Don't** do this: def my_stmt(parameter, thing=False): stmt = lambda_stmt(lambda: select(table)) stmt += lambda s: ( s.where(table.c.x > parameter) if thing else s.where(table.c.y == parameter) ) return stmt # **Do** do this: def my_stmt(parameter, thing=False): stmt = lambda_stmt(lambda: select(table)) if thing: stmt += lambda s: s.where(table.c.x > parameter) else: stmt += lambda s: s.where(table.c.y == parameter) return stmt
如果 lambda 没有产生一致的 SQL 结构,则可能会发生各种故障,有些故障目前无法轻松检测到。
请勿使用 lambda 内的函数来生成绑定值 - 该 bound value 跟踪方式要求实际值在 SQL 语句本地存在于 lambda 的闭包中。 这是 如果值是从其他函数生成的,则不可能,并且 如果尝试这样做,LambdaElement
通常会引发错误:>>> def my_stmt(x, y): ... def get_x(): ... return x ... ... def get_y(): ... return y ... ... stmt = lambda_stmt(lambda: select(func.max(get_x(), get_y()))) ... return stmt >>> with engine.connect() as conn: ... print(conn.scalar(my_stmt(5, 10))) Traceback (most recent call last): # ... sqlalchemy.exc.InvalidRequestError: Can't invoke Python callable get_x() inside of lambda expression argument at <code object <lambda> at 0x7fed15f350e0, file "<stdin>", line 6>; lambda SQL constructs should not invoke functions from closure variables to produce literal values since the lambda SQL system normally extracts bound values without actually invoking the lambda or any functions within it.
在上面,如果需要,get_x()
和get_y() 的使用
应该在 lambda 之外进行,并分配给局部闭包变量:>>> def my_stmt(x, y): ... def get_x(): ... return x ... ... def get_y(): ... return y ... ... x_param, y_param = get_x(), get_y() ... stmt = lambda_stmt(lambda: select(func.max(x_param, y_param))) ... return stmt
避免在 lambda 中引用非 SQL 结构,因为它们不是 cacheable - 此问题是指LambdaElement
从语句中的其他 Closure 变量创建缓存键。 挨次 为了最好地保证缓存键的准确,所有对象都位于 在 lambda 的闭包中被认为是重要的,并且没有 默认情况下,将假定为适合缓存键。 因此,以下示例还将引发相当详细的错误消息:>>> class Foo: ... def __init__(self, x, y): ... self.x = x ... self.y = y >>> def my_stmt(foo): ... stmt = lambda_stmt(lambda: select(func.max(foo.x, foo.y))) ... return stmt >>> with engine.connect() as conn: ... print(conn.scalar(my_stmt(Foo(5, 10)))) Traceback (most recent call last): # ... sqlalchemy.exc.InvalidRequestError: Closure variable named 'foo' inside of lambda callable <code object <lambda> at 0x7fed15f35450, file "<stdin>", line 2> does not refer to a cacheable SQL element, and also does not appear to be serving as a SQL literal bound value based on the default SQL expression returned by the function. This variable needs to remain outside the scope of a SQL-generating lambda so that a proper cache key may be generated from the lambda's state. Evaluate this variable outside of the lambda, set track_on=[<elements>] to explicitly select closure elements to track, or set track_closure_variables=False to exclude closure variables from being part of the cache key.
上述错误表明LambdaElement
不会假定传入的Foo
对象在所有情况下都将继续保持相同的行为。默认情况下,它也不会假设它可以使用Foo
作为缓存键的一部分;如果它使用Foo
对象作为缓存键的一部分,如果有许多不同的Foo
对象,这将用重复的信息填充缓存,并且还将保存对所有这些对象的长期引用。
解决上述情况的最好办法是不要引用foo
在 lambda 内部,并在外部引用它:>>> def my_stmt(foo): ... x_param, y_param = foo.x, foo.y ... stmt = lambda_stmt(lambda: select(func.max(x_param, y_param))) ... return stmt
在某些情况下,如果保证 lambda 的 SQL 结构永远不会根据输入而改变,则传递track_closure_variables=False
这将禁用除 用于绑定参数:>>> def my_stmt(foo): ... stmt = lambda_stmt( ... lambda: select(func.max(foo.x, foo.y)), track_closure_variables=False ... ) ... return stmt
还可以使用track_on
参数将对象添加到元素以显式形成缓存键的一部分;使用此参数允许特定值用作缓存键,并且还将防止考虑其他 Closure 变量。这对于正在构建的 SQL 的一部分源自可能具有许多不同值的某种上下文对象的情况非常有用。在下面的示例中,SELECT 语句的第一段将禁用对foo
变量的跟踪,而第二段将显式跟踪self
作为缓存键的一部分:>>> def my_stmt(self, foo): ... stmt = lambda_stmt( ... lambda: select(*self.column_expressions), track_closure_variables=False ... ) ... stmt = stmt.add_criteria(lambda: self.where_criteria, track_on=[self]) ... return stmt
使用track_on
意味着给定对象将长期存储在 Lambda 的内部缓存中,并且只要缓存不清除这些对象,就会具有强引用(默认情况下使用 1000 个条目的 LRU 方案)。
缓存密钥生成¶
为了了解 lambda SQL 构造中出现的一些选项和行为,了解缓存系统会很有帮助。
SQLAlchemy 的缓存系统通常通过生成表示构造中所有状态的结构来从给定的 SQL 表达式构造生成缓存键:
>>> from sqlalchemy import select, column
>>> stmt = select(column("q"))
>>> cache_key = stmt._generate_cache_key()
>>> print(cache_key) # somewhat paraphrased
CacheKey(key=(
'0',
<class 'sqlalchemy.sql.selectable.Select'>,
'_raw_columns',
(
(
'1',
<class 'sqlalchemy.sql.elements.ColumnClause'>,
'name',
'q',
'type',
(
<class 'sqlalchemy.sql.sqltypes.NullType'>,
),
),
),
# a few more elements are here, and many more for a more
# complicated SELECT statement
),)
上面的键存储在缓存中,缓存本质上是一个字典,值是一个结构,除其他外,它存储 SQL 语句的字符串形式,在本例中为短语 “SELECT q”。我们可以观察到,即使对于极短的查询,缓存键也非常冗长,因为它必须表示与正在渲染和可能执行的内容可能发生变化的所有内容。
相比之下,lambda 构造系统会创建不同类型的缓存键:
>>> from sqlalchemy import lambda_stmt
>>> stmt = lambda_stmt(lambda: select(column("q")))
>>> cache_key = stmt._generate_cache_key()
>>> print(cache_key)
CacheKey(key=(
<code object <lambda> at 0x7fed1617c710, file "<stdin>", line 1>,
<class 'sqlalchemy.sql.lambdas.StatementLambdaElement'>,
),)
在上面,我们看到一个缓存键比非 lambda 语句的缓存键短得多,此外,select(column(“q”))
的生成
构造本身甚至不是必需的;Python lambda 本身包含
一个名为 __code__
的属性,它指的是一个 Python 代码对象,该对象在应用程序的运行时内是不可变的和永久的。
当 lambda 还包含闭包变量时,在正常情况下,这些变量引用 SQL 结构(如列对象)时,它们将成为缓存键的一部分,或者如果它们引用将成为绑定参数的文字值,则它们将被放置在缓存键的单独元素中:
>>> def my_stmt(parameter):
... col = column("q")
... stmt = lambda_stmt(lambda: select(col))
... stmt += lambda s: s.where(col == parameter)
... return stmt
上面的 StatementLambdaElement
包含两个 lambda,这两个 lambda 都引用 col
闭包变量,因此缓存键将表示这两个段以及 column()
对象:
>>> stmt = my_stmt(5)
>>> key = stmt._generate_cache_key()
>>> print(key)
CacheKey(key=(
<code object <lambda> at 0x7f07323c50e0, file "<stdin>", line 3>,
(
'0',
<class 'sqlalchemy.sql.elements.ColumnClause'>,
'name',
'q',
'type',
(
<class 'sqlalchemy.sql.sqltypes.NullType'>,
),
),
<code object <lambda> at 0x7f07323c5190, file "<stdin>", line 4>,
<class 'sqlalchemy.sql.lambdas.LinkedLambdaElement'>,
(
'0',
<class 'sqlalchemy.sql.elements.ColumnClause'>,
'name',
'q',
'type',
(
<class 'sqlalchemy.sql.sqltypes.NullType'>,
),
),
(
'0',
<class 'sqlalchemy.sql.elements.ColumnClause'>,
'name',
'q',
'type',
(
<class 'sqlalchemy.sql.sqltypes.NullType'>,
),
),
),)
缓存键的第二部分检索了调用语句时将使用的绑定参数:
>>> key.bindparams
[BindParameter('%(139668884281280 parameter)s', 5, type_=Integer())]
有关具有性能比较的“lambda”缓存的一系列示例,short_selects请参阅性能
性能示例。
INSERT 语句的 “Insert Many Values” 行为¶
2.0 新版功能: 有关更改的背景信息,包括示例性能测试,请参阅现在为除 MySQL 以外的所有后端实施优化的 ORM 批量插入
提示
insertmanyvalues 功能是透明可用的
性能功能,无需最终用户干预即可
它根据需要进行。 本节介绍体系结构
以及如何衡量其性能和调整其
行为以优化批量 INSERT 语句的速度,
特别是 ORM 使用的。
随着更多的数据库增加了对 INSERT..RETURNING,SQLAlchemy 具有
在处理 INSERT 语句主题的方式上发生了重大变化
需要获取服务器生成的值,最重要的是
服务器生成的主键值,允许在
后续作。特别是,这种情况长期以来一直是一个重要的
性能问题,它依赖于能够检索
服务器生成的主键值,以便正确填充
身份映射。
随着最近在 SQLite 和 MariaDB 中添加了对 RETURNING 的支持,SQLAlchemy 没有
longer 需要依赖单行的
cursor.lastrowid 属性;RETURNING 现在可以用于所有包含 SQLAlchemy 的后端,但
的 MySQL。剩余性能
限制,则
cursor.executemany()DBAPI 方法不允许获取行,对于大多数后端,通过放弃使用 executemany()
并改建单个 INSERT 语句,每个语句在使用 cursor.execute()
调用的单个语句中容纳大量行来解决。这种方法源于
从
psycopg2 快速执行帮助程序
psycopg2
DBAPI 的功能,SQLAlchemy 在最近的版本系列中逐步添加了越来越多的支持。
当前支持¶
为 SQLAlchemy 中包含的所有支持
RETURNING,但 Oracle Database 除外,其中
python-oracledb 和 cx_Oracle 驱动程序提供自己的等效功能。这
功能通常在使用
Insert 结构的 Insert.returning()
方法与 executemany 执行结合使用,这在将字典列表传递给
Connection.execute.parameters
时发生
parameter
或
Session.execute()
方法(以及
asyncio 和速记方法(如
Session.scalars())的 Session.scalars)。
它也发生在 ORM 单元内
使用 Session.add()
和
Session.add_all()
添加行。
对于 SQLAlchemy 包含的方言,支持或等效支持目前如下:
SQLite - 支持 SQLite 版本 3.35 及更高版本
PostgreSQL - 所有支持的 Postgresql 版本(9 及更高版本)
SQL Server - 所有支持的 SQL Server 版本 [1]
MariaDB - 支持 MariaDB 版本 10.5 及更高版本
MySQL - 不支持,不存在 RETURNING 功能
Oracle Database - 对于所有受支持的 Oracle Database 版本 9 及更高版本,使用多行 OUT 参数,支持使用本机 python-oracledb/cx_Oracle API 通过 executemany 进行 RETURNING。这与 “executemanyvalues” 不同,但具有相同的使用模式和等效的性能优势。
在 2.0.10 版本发生变更:
禁用该功能¶
要为
Engine
整体上,将
create_engine.use_insertmanyvalues
parameter 设置为 False
create_engine()
中:
engine = create_engine(
"mariadb+mariadbconnector://scott:tiger@host/db", use_insertmanyvalues=False
)
还可以禁止该功能隐式用于特定的
Table
对象,方法是将
Table.implicit_returning
参数设置为 False
:
t = Table(
"t",
metadata,
Column("id", Integer, primary_key=True),
Column("x", Integer),
implicit_returning=False,
)
人们可能想要为特定 table 禁用 RETURNING 的原因是为了解决特定于后端的限制。
批处理模式作¶
该功能有两种作模式,它们是基于每个方言、每个表
透明地选择的。一种是批处理模式,它通过重写以下形式的 INSERT 语句来减少数据库往返的次数:
INSERT INTO a (data, x, y) VALUES (%(data)s, %(x)s, %(y)s) RETURNING a.id
转换为“批处理”形式,例如:
INSERT INTO a (data, x, y) VALUES
(%(data_0)s, %(x_0)s, %(y_0)s),
(%(data_1)s, %(x_1)s, %(y_1)s),
(%(data_2)s, %(x_2)s, %(y_2)s),
...
(%(data_78)s, %(x_78)s, %(y_78)s)
RETURNING a.id
在上面,语句是针对输入数据的子集(“批次”)组织的,其大小由数据库后端以及每个批次中的参数数量决定,以对应于语句大小/参数数量的已知限制。然后,该功能对每批输入数据执行一次 INSERT 语句,直到所有记录都用完,将每批的 RETURNING 结果连接到单个大型行集中,该行集可从单个 Result
对象获得。
这种 “batched” 形式允许使用更少的数据库往返来回执行多行的 INSERT,并且已被证明可以显著提高大多数支持它的后端的性能。
将 RETURNING 行与参数集相关联¶
在 2.0.10 版本加入.
上一节中说明的 “batch” 模式查询不能保证返回的记录顺序与输入数据的顺序相对应。当由 SQLAlchemy ORM 工作进程单元使用时,以及用于将返回的服务器生成的值与输入数据相关联的应用程序时,Insert.returning()
和 UpdateBase.return_defaults()
方法包含一个选项
Insert.returning.sort_by_parameter_order
这表示 “insertmanyvalues” 模式应保证这种对应。这不是
与数据库后端实际 INSERTed 记录的顺序相关,这在任何情况下都不会假设;只是返回的记录在收到时应进行组织,以对应于原始输入数据的传递顺序。
当该 Insert.returning.sort_by_parameter_order
参数存在时,对于使用服务器生成的整数主键值(如 IDENTITY、
PostgreSQL SERIAL、
MariaDB AUTO_INCREMENT
或 SQLite 的
ROWID
方案,“批处理”模式可能会选择使用更复杂的 INSERT..RETURNING 形式,结合根据返回值对行的执行后排序,或者如果此类形式不可用,则“insertmanyvalues”功能可能会正常降级为“非批处理”模式,该模式为每个参数集运行单独的 INSERT 语句。
例如,在 SQL Server 上,当使用自动递增的 IDENTITY
列作为主键时,将使用以下 SQL 格式:
INSERT INTO a (data, x, y)
OUTPUT inserted.id, inserted.id AS id__1
SELECT p0, p1, p2 FROM (VALUES
(?, ?, ?, 0), (?, ?, ?, 1), (?, ?, ?, 2),
...
(?, ?, ?, 77)
) AS imp_sen(p0, p1, p2, sen_counter) ORDER BY sen_counter
当主键列使用 SERIAL 或 IDENTITY 时,PostgreSQL 也使用类似的形式。上述表单不保证行的插入顺序。但是,它确实保证了 IDENTITY 或 SERIAL 值将按顺序创建每个参数集 [2]。然后,“insertmanyvalues” 功能通过递增整数标识对上述 INSERT 语句的返回行进行排序。
对于 SQLite 数据库,没有合适的 INSERT 表单可以将新 ROWID 值的生成与参数集的传递顺序相关联。因此,当使用服务器生成的主键值时,当请求有序 RETURNING 时, SQLite 后端将降级为“非批处理”模式。对于 MariaDB,insertmanyvalues 使用的默认 INSERT 形式就足够了,因为在使用 InnoDB 时,此数据库后端会将AUTO_INCREMENT的顺序与输入数据的顺序对齐 [3]。
对于客户端生成的主键,例如使用 Python
uuid.uuid4()
函数为 Uuid
列生成新值时,“insertmanyvalues”功能以透明方式将此列包含在 RETURNING 记录中,并将其值与给定输入记录的值相关联,从而保持输入记录和结果行之间的对应关系。由此可见,当使用客户端生成的主键值时,所有后端都允许批量的、与参数相关的 RETURNING 顺序。
“insertmanyvalues” “batch” 模式如何确定要用作输入参数和 RETURNING 行之间的对应点的一列或多列的主题称为插入哨兵,它是一个特定的
列或列。“插入哨兵”是
通常自动选择,但也可以是用户配置
极其特殊的情况;该部分
配置 Sentinel 列 对此进行了介绍。
对于不提供适当的 INSERT 表单的后端,这些表单可以传递服务器生成的值与输入值确定性地对齐,或者对于具有其他类型的服务器生成的主键值的表
配置,“insertmanyvalues”模式将在请求保证的 RETURNING 排序时使用非批处理模式。
另请参阅
[2]
Microsoft SQL Server 理由
“使用 SELECT 和 ORDER BY 填充行的 INSERT 查询可以保证 如何计算标识值,而不是行的插入顺序。 https://learn.microsoft.com/en-us/sql/t-sql/statements/insert-transact-sql?view=sql-server-ver16#limitations-and-restrictions
PostgreSQL 批处理 INSERT 讨论
原始描述:2018 https://www.postgresql.org/message-id/29386.1528813619@sss.pgh.pa.us
2023 年跟进 - https://www.postgresql.org/message-id/be108555-da2a-4abc-a46b-acbe8b55bd25%40app.fastmail.com[3]
MariaDB AUTO_INCREMENT行为(使用与 MySQL 相同的 InnoDB 引擎):https://dev.mysql.com/doc/refman/8.0/en/innodb-auto-increment-handling.html
非批处理模式作¶
对于没有客户端主数据库的表
配置
key 值,并提供服务器生成的主键值(或无主键)
相关数据库无法在确定性或
相对于多个参数集的可排序方式,“insertManyValues”
功能在满足
Insert.returning.sort_by_parameter_order
要求
Insert
语句可能会选择使用非批处理模式。
在这种模式下,将保留 INSERT 的原始 SQL 形式,并且 “insertmanyvalues” 功能将按照为每个参数集单独给定的语句运行语句,将返回的行组织成一个完整的结果集。与以前的 SQLAlchemy 版本不同,它在紧密的循环中执行此作,从而最大限度地减少 Python 开销。在某些情况下,例如在 SQLite 上,“非批处理”模式的性能与“批处理”模式完全相同。
语句执行模型¶
对于 “batched” 和 “non-batched” 模式,该功能必须在对 Core 级别的单次调用范围内使用 DBAPI cursor.execute()
方法调用多个 INSERT 语句
Connection.execute()
方法,每个语句最多包含固定数量的参数集。此限制可配置,如下文控制批次大小中所述。对 cursor.execute()
的单独调用是单独记录的,并且
也单独传递给事件侦听器,例如
ConnectionEvents.before_cursor_execute()
(请参阅 日志记录和事件
)。
配置 Sentinel 列¶
在典型情况下,“insertmanyvalues” 功能为了提供 INSERT..具有确定性行顺序的 RETURNING 将自动从给定表的主键中确定 sentinel 列,如果无法识别,则正常降级为 “row at time ”(一次行) 模式。作为完全可选的
功能,以获得具有
服务器生成的主键,其默认生成器函数不是
与 “Sentinel” 用例兼容,其他非主键列可能
标记为 “Sentinel” 列,假设它们满足特定要求。一个典型的
example 是具有客户端默认值的非主键 Uuid
列,例如 Python uuid.uuid4()
函数。还有一个构造可以创建简单的整数列,其中包含面向 “insertmanyvalues” 用例的客户端整数计数器。
可以通过添加 Sentinel 列来指示Column.insert_sentinel
限定列。 最基本的 “qualifying” 列是不可为 null的
unique 列,例如 UUID 列,如下所示:
import uuid
from sqlalchemy import Column
from sqlalchemy import FetchedValue
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy import Table
from sqlalchemy import Uuid
my_table = Table(
"some_table",
metadata,
# assume some arbitrary server-side function generates
# primary key values, so cannot be tracked by a bulk insert
Column("id", String(50), server_default=FetchedValue(), primary_key=True),
Column("data", String(50)),
Column(
"uniqueid",
Uuid(),
default=uuid.uuid4,
nullable=False,
unique=True,
insert_sentinel=True,
),
)
当使用 ORM 声明式模型时,使用 mapped_column
构造可以使用相同的形式:
import uuid
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
class Base(DeclarativeBase):
pass
class MyClass(Base):
__tablename__ = "my_table"
id: Mapped[str] = mapped_column(primary_key=True, server_default=FetchedValue())
data: Mapped[str] = mapped_column(String(50))
uniqueid: Mapped[uuid.UUID] = mapped_column(
default=uuid.uuid4, unique=True, insert_sentinel=True
)
虽然 default 生成器生成的值必须是唯一的,
实际的 UNIQUE 约束,由
unique=True
参数,它本身是可选的,如果不需要,可以省略。
还有一种特殊形式的 “insert sentinel”,它是一个专用的可为 null 的整数列,它使用仅在 “insertmanyvalues”作期间使用的特殊默认整数计数器;作为附加行为,该列将从 SQL 语句和结果集中省略自身,并以几乎透明的方式运行。但是,它确实需要实际存在于实际的数据库表中。此样式的 Column
可以使用函数 insert_sentinel()
构造:
from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy import Table
from sqlalchemy import Uuid
from sqlalchemy import insert_sentinel
Table(
"some_table",
metadata,
Column("id", Integer, primary_key=True),
Column("data", String(50)),
insert_sentinel("sentinel"),
)
当使用 ORM Declare 时,声明友好版本的
insert_sentinel()
可用,称为
orm_insert_sentinel(),
它能够用于 Base 类或 mixin;如果使用 declared_attr()
打包,则该列将应用于所有 table 绑定的子类,包括在联接的继承层次结构中:
from sqlalchemy.orm import declared_attr
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import orm_insert_sentinel
class Base(DeclarativeBase):
@declared_attr
def _sentinel(cls) -> Mapped[int]:
return orm_insert_sentinel()
class MyClass(Base):
__tablename__ = "my_table"
id: Mapped[str] = mapped_column(primary_key=True, server_default=FetchedValue())
data: Mapped[str] = mapped_column(String(50))
class MySubClass(MyClass):
__tablename__ = "sub_table"
id: Mapped[str] = mapped_column(ForeignKey("my_table.id"), primary_key=True)
class MySingleInhClass(MyClass):
pass
在上面的示例中,“my_table” 和 “sub_table” 都将有一个名为 “_sentinel” 的额外整数列,“insertmanyvalues” 功能可以使用该列来帮助优化 ORM 使用的批量插入。
控制 Batch 大小¶
“insertmanyvalues” 的一个关键特征是 INSERT 语句的大小受到固定的 “values” 子句的最大数量以及特定于方言的固定绑定参数总数的限制,这些参数一次可以在一个 INSERT 语句中表示。当给定的参数字典数量超过固定限制时,或者当单个 INSERT 语句中要呈现的绑定参数总数超过固定限制时(两个固定限制是分开的),将在单个 Connection.execute()
调用的范围内调用多个 INSERT 语句,每个语句容纳一部分参数字典。 称为 “批次”。每个 “batch” 中表示的参数字典的数量称为 “batch size”。例如,批处理大小为 500 意味着发出的每个 INSERT 语句将最多包含 500 行 INSERT。
能够调整批处理大小可能很重要,因为较大的批处理大小对于值集本身相对较小的 INSERT 可能性能更高,而较小的批处理大小可能更适合使用非常大的值集的 INSERT,其中呈现的 SQL 的大小以及在一个语句中传递的总数据大小都可能受益于限制为基于后端行为和内存约束的特定大小。因此,可以基于每个 Engine
和每个语句配置批处理大小。另一方面,参数限制是根据正在使用的数据库的已知特征固定的。
对于大多数后端,批处理大小默认为 1000,并且有一个额外的每方言“最大参数数”限制因子,这可能会进一步减少每个语句的批处理大小。最大参数数因方言和服务器版本而异;最大大小为 32700(选择与 PostgreSQL 的限制 32767 和 SQLite 的现代限制 32766 保持健康距离,同时为语句中的其他参数以及 DBAPI 古怪留出空间)。旧版本的 SQLite(3.32.0 之前)会将此值设置为 999。MariaDB 没有既定的限制,但 32700 仍然是 SQL 消息大小的限制因素。
“batch size” 的值可能会受到影响 Engine
wide 的 create_engine.insertmanyvalues_page_size
例如,要影响 INSERT 语句在每个语句中包含最多 100 个参数集:
e = create_engine("sqlite://", insertmanyvalues_page_size=100)
批处理大小也可能在使用
Connection.execution_options.insertmanyvalues_page_size
执行选项,例如 Per Execution:
with e.begin() as conn:
result = conn.execute(
table.insert().returning(table.c.id),
parameterlist,
execution_options={"insertmanyvalues_page_size": 100},
)
或者在语句本身上配置:
stmt = (
table.insert()
.returning(table.c.id)
.execution_options(insertmanyvalues_page_size=100)
)
with e.begin() as conn:
result = conn.execute(stmt, parameterlist)
日志和事件¶
“insertmanyvalues” 功能与 SQLAlchemy 的语句完全集成
logging 以及游标事件(如 ConnectionEvents.before_cursor_execute()
.当参数列表被分成单独的批次时,每个 INSERT
语句被记录下来并单独传递给事件处理程序。与以前的 SQLAlchemy 1.x 系列中仅 psycopg2 功能的工作方式相比,这是一个重大变化,在之前的 SQLAlchemy 系列中,多个 INSERT 语句的生成在日志记录和事件中是隐藏的。日志记录显示将截断长长的参数列表以提高可读性,并且还会指示每个语句的特定批次。以下示例说明了此日志记录的摘录:
INSERT INTO a (data, x, y) VALUES (?, ?, ?), ... 795 characters truncated ... (?, ?, ?), (?, ?, ?) RETURNING id
[generated in 0.00177s (insertmanyvalues) 1/10 (unordered)] ('d0', 0, 0, 'd1', ...
INSERT INTO a (data, x, y) VALUES (?, ?, ?), ... 795 characters truncated ... (?, ?, ?), (?, ?, ?) RETURNING id
[insertmanyvalues 2/10 (unordered)] ('d100', 100, 1000, 'd101', ...
...
INSERT INTO a (data, x, y) VALUES (?, ?, ?), ... 795 characters truncated ... (?, ?, ?), (?, ?, ?) RETURNING id
[insertmanyvalues 10/10 (unordered)] ('d900', 900, 9000, 'd901', ...
当非批处理模式发生时,日志记录将与 insertmanyvalues 消息一起指示这一点:
...
INSERT INTO a (data, x, y) VALUES (?, ?, ?) RETURNING id
[insertmanyvalues 67/78 (ordered; batch not supported)] ('d66', 66, 66)
INSERT INTO a (data, x, y) VALUES (?, ?, ?) RETURNING id
[insertmanyvalues 68/78 (ordered; batch not supported)] ('d67', 67, 67)
INSERT INTO a (data, x, y) VALUES (?, ?, ?) RETURNING id
[insertmanyvalues 69/78 (ordered; batch not supported)] ('d68', 68, 68)
INSERT INTO a (data, x, y) VALUES (?, ?, ?) RETURNING id
[insertmanyvalues 70/78 (ordered; batch not supported)] ('d69', 69, 69)
...
另请参阅
Upsert 支持¶
PostgreSQL、SQLite 和 MariaDB 方言提供特定于后端的“upsert”结构 insert()、
insert()
和 insert(),
它们都是具有附加方法(如
on_conflict_do_update()` or
``on_duplicate_key()
.这些结构在与 RETURNING 一起使用时还支持“insertmanyvalues”行为,从而允许使用 RETURNING 进行高效的更新插入。
引擎处置¶
Engine
指的是一个连接池,意思是在正常情况下
情况下,存在打开的数据库连接,而
Engine
对象仍驻留在内存中。当引擎
被垃圾回收,则其连接池不再由
该 Engine
,并且假设它的所有连接都未被签出,则池及其连接也将被垃圾回收,这也具有关闭实际数据库连接的效果。但除此之外,Engine
将保留打开的数据库连接,假设它使用 QueuePool
的通常默认池实现。
引擎
通常是预先建立的永久性固定装置,并在应用程序的整个生命周期内进行维护。它不应基于每个连接创建和处置;相反,它是一个注册表,它维护一个连接池以及有关正在使用的数据库和 DBAPI 的配置信息,以及每个数据库资源的某种程度的内部缓存。
但是,在许多情况下,希望完全关闭 Engine
引用的所有连接资源。在这些情况下,依赖 Python 垃圾回收通常不是一个好主意;相反,可以使用 Engine.dispose()
方法显式释放 Engine
。这将处理引擎的底层连接池,并将其替换为一个空的新连接池。前提是 Engine
此时被丢弃并且不再使用,则它引用的所有检入连接也将完全关闭。
调用 Engine.dispose()
的有效用例包括:
当程序想要释放连接池持有的任何剩余签入连接,并希望不再连接到该数据库以执行任何将来的作时。
当程序使用 multiprocessing 或fork()
时,并且Engine
对象复制到子进程, 应该调用Engine.dispose()
,以便引擎在该 fork 本地创建全新的数据库连接。数据库连接通常不会跨越进程边界。 使用在这种情况下,Engine.dispose.close
参数设置为 False。有关此用例的更多背景信息,请参阅将连接池与 Multiprocessing 结合使用或 os.fork() 部分。
在测试套件或多租户场景中,可以创建和释放许多临时的、短期的Engine
对象。
在释放引擎或进行垃圾回收时,不会丢弃已签出的连接,因为这些连接仍由应用程序在其他位置强引用。但是,在调用 Engine.dispose()
后,这些连接不再与该 Engine
关联;当他们
已关闭,它们将被返回到现在孤立的连接池中
最终将被垃圾回收,一旦所有引用
也不再在任何地方引用它。
由于此过程不易控制,因此强烈建议
只有在签入所有签出的连接或以其他方式从其池中取消关联后,才会调用 Engine.dispose()。
受
Engine
对象使用连接池是为了完全禁用池。这通常对使用新连接仅产生适度的性能影响,并且意味着当连接被签入时,它将完全关闭并且不会保存在内存中。请参阅 切换池实施
有关如何禁用池化的指南。
使用驱动程序 SQL 和原始 DBAPI 连接¶
关于使用 Connection.execute()
的介绍使用了
text()
结构来说明文本 SQL 语句如何
可以调用。 当使用 SQLAlchemy 时,文本 SQL 实际上更
作为 Core 表达式语言
和 ORM 都抽象出 SQL 的文本表示。 但是,
text()
结构本身还提供了文本 SQL 的一些抽象,因为它规范了绑定参数的传递方式,并且它支持参数和结果集行的数据类型行为。
直接向驱动程序调用 SQL 字符串¶
对于想要调用直接传递给底层驱动程序(称为 DBAPI)的文本 SQL,而无需 text()
结构的任何干预的用例,Connection.exec_driver_sql()
方法可能使用:
with engine.connect() as conn:
conn.exec_driver_sql("SET param='bar'")
1.4 版本中的新功能: 添加了 Connection.exec_driver_sql()
方法。
直接使用 DBAPI 游标¶
在某些情况下,SQLAlchemy 不提供访问某些 DBAPI 函数(如调用存储过程以及处理多个结果集)的通用方法。在这些情况下,直接处理原始 DBAPI 连接同样方便。
访问原始 DBAPI 连接的最常见方法是直接从已存在的 Connection
对象获取它。它使用 Connection.connection
属性存在:
connection = engine.connect()
dbapi_conn = connection.connection
这里的 DBAPI 连接实际上是原始连接池的 “代理”,但是这是一个在大多数情况下可以忽略的实现细节。由于此 DBAPI 连接仍包含在拥有的 Connection
对象的范围内,因此最好将 Connection
对象用于大多数功能,例如事务控制以及调用 Connection.close()
方法;如果这些作直接在 DBAPI 连接上执行,
拥有的 Connection
不会意识到这些状态变化。
为了克服由拥有连接
维护的 DBAPI 连接所施加的限制,DBAPI 连接也是
无需购买
首先连接
,使用 Engine
的 Engine.raw_connection()
方法:
dbapi_conn = engine.raw_connection()
与以前一样,此 DBAPI 连接再次成为 “代理” 形式。这个代理的目的现在很明显了,就像我们调用 .close()
时一样
方法,则 DBAPI 连接通常实际上不是
closed,而是释放回引擎的连接池:
dbapi_conn.close()
虽然 SQLAlchemy 将来可能会为更多 DBAPI 用例添加内置模式,但回报会递减,因为这些情况往往很少需要,而且它们也高度依赖于所使用的 DBAPI 类型,因此在任何情况下,直接 DBAPI 调用模式始终适用于需要它的情况。
另请参阅
使用 Engine 时如何获取原始 DBAPI 连接?- 包括有关如何访问 DBAPI 连接以及使用 asyncio 驱动程序时的“driver”连接的其他详细信息。
下面是一些 DBAPI 连接使用的配方。
调用存储过程和用户定义的函数¶
SQLAlchemy 支持以多种方式调用存储过程和用户定义的函数。请注意,所有 DBAPI 都有不同的做法,因此您必须查阅基础 DBAPI 的文档,了解与您的特定用法相关的详细信息。以下示例是假设的,可能不适用于您的底层 DBAPI。
对于具有特殊语法或参数问题的存储过程或函数,DBAPI 级别的 callproc
可能会与您的 DBAPI 一起使用。此模式的一个示例是:
connection = engine.raw_connection()
try:
cursor_obj = connection.cursor()
cursor_obj.callproc("my_procedure", ["x", "y", "z"])
results = list(cursor_obj.fetchall())
cursor_obj.close()
connection.commit()
finally:
connection.close()
注意
并非所有 DBAPI 都使用 callproc,总体使用情况详细信息会有所不同。上面的示例只是使用特定 DBAPI 函数的一个说明。
您的 DBAPI 可能没有 callproc
要求,或者可能需要存储的
过程或用户定义的函数,例如
正常的 SQLAlchemy 连接使用。这种使用模式的一个示例是:
在撰写本文档时,使用 psycopg2 DBAPI 在 PostgreSQL 数据库中执行存储过程,该存储过程应使用正常连接使用调用:
connection.execute("CALL my_procedure();")
上面的例子是假设的。在这些情况下,不保证基础数据库支持 “CALL” 或 “SELECT”,并且关键字可能会因函数是存储过程还是用户定义的函数而异。在这些情况下,您应该查阅基础 DBAPI 和数据库文档,以确定要使用的正确语法和模式。
多个结果集¶
使用原始 DBAPI 游标提供多结果集支持,使用
nextset 方法:
connection = engine.raw_connection()
try:
cursor_obj = connection.cursor()
cursor_obj.execute("select * from table1; select * from table2")
results_one = cursor_obj.fetchall()
cursor_obj.nextset()
results_two = cursor_obj.fetchall()
cursor_obj.close()
finally:
connection.close()
注册新方言¶
create_engine()
函数调用使用 setuptools 入口点定位给定的方言。可以在 setup.py 脚本中为第三方方言建立这些入口点。例如,要创建一个新的方言 “foodialect://”,步骤如下:
创建一个名为foodialect
的包。
该包应具有一个包含 dialect 类的模块,该类通常是sqlalchemy.engine.default.DefaultDialect
.在这个例子中,假设它叫做FooDialect
,它的模块是通过foodialect.dialect
访问的。
入口点可以在setup.cfg
中建立,如下所示:[options.entry_points] sqlalchemy.dialects = foodialect = foodialect.dialect:FooDialect
如果方言在现有的 SQLAlchemy 支持的数据库之上为特定 DBAPI 提供支持,则可以给出名称,包括 database-qualification。例如,如果 FooDialect
实际上是 MySQL 方言,则可以像这样建立入口点:
[options.entry_points]
sqlalchemy.dialects
mysql.foodialect = foodialect.dialect:FooDialect
然后,上述入口点将作为 create_engine("mysql+foodialect://")
.
进程内注册 dialect¶
SQLAlchemy 还允许在当前进程中注册方言,而无需单独安装。按如下方式使用 register()
函数:
from sqlalchemy.dialects import registry
registry.register("mysql.foodialect", "myapp.dialect", "MyMySQLDialect")
上面将响应 create_engine("mysql+foodialect://")
并加载
myapp.dialect
模块中的 MyMySQLDialect
类。
连接 / 引擎 API¶
对象名称 |
描述 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
-
类 sqlalchemy.engine 中。连接¶
为包装的 DB-API 连接提供高级功能。Connection
对象是通过调用Engine.connect()
方法对象,并提供执行 SQL 语句的服务 作为事务控制。
Connection 对象不是线程安全的。虽然可以使用正确同步的访问在线程之间共享 Connection,但底层 DBAPI 连接仍可能不支持线程之间的共享访问。有关详细信息,请查看 DBAPI 文档。
成员
__init__()、begin()、begin_nested()、begin_twophase()、close()、closed、commit()、connection、default_isolation_level、detach()、exec_driver_sql()、execute()、execution_options()get_execution_options(), get_isolation_level(), get_nested_transaction(), get_transaction(), in_nested_transaction(), in_transaction(), info, invalidate(), 无效, 回滚(), 标量(), 标量(), schema_for_object()
Connection 对象表示从连接池中签出的单个 DBAPI 连接。在此状态下,连接池对连接没有影响,包括其过期或超时状态。为了使连接池正确管理连接,只要连接未使用,就应将连接返回到连接池(即connection.close()
)。
类签名
类sqlalchemy.engine.Connection
(sqlalchemy.engine.interfaces.ConnectionEventsTarget
,sqlalchemy.inspection.Inspectable
)-
方法sqlalchemy.engine.Connection 中。
__init__(engine: Engine, connection:PoolProxiedConnectionNone=None, _has_events:boolNone=None, _allow_revalidate: bool = True, _allow_autobegin: bool = True)¶
构造新的 Connection。
-
方法sqlalchemy.engine.Connection 中。
begin()RootTransaction ¶
在 autostart 发生之前开始事务。
例如:with engine.connect() as conn: with conn.begin() as trans: conn.execute(table.insert(), {"username": "sandy"})
返回的对象是RootTransaction
的实例。此对象表示事务的 “范围”,当Transaction.rollback()
或Transaction.commit()
方法;该对象还用作上下文管理器,如上所示。Connection.begin()
方法开始一个事务,该事务通常在任何情况下都会在连接首次用于执行语句时开始。使用此方法的原因是调用ConnectionEvents.begin()
事件,或者在 根据上下文 Management 块进行连接检出,例如:with engine.connect() as conn: with conn.begin(): conn.execute(...) conn.execute(...) with conn.begin(): conn.execute(...) conn.execute(...)
上面的代码在行为上与 以下代码不使用Connection.begin()
;以下样式称为 “Commit as you go” 样式:with engine.connect() as conn: conn.execute(...) conn.execute(...) conn.commit() conn.execute(...) conn.execute(...) conn.commit()
从数据库的角度来看,Connection.begin()
方法不会发出任何 SQL 或更改底层的状态 以任何方式建立 DBAPI 连接;Python DBAPI 没有任何 显式事务 begin 的概念。
另请参阅
使用事务和 DBAPI - 在 SQLAlchemy Unified 教程Connection.begin_nested()
- 使用 SAVEPOINTConnection.begin_twophase()
- 使用两阶段 /XID 事务Engine.begin()
- 可从发动机
-
方法sqlalchemy.engine.Connection 中。
begin_nested()NestedTransaction ¶
开始一个嵌套事务(即 SAVEPOINT)并返回一个控制 SAVEPOINT 范围的事务句柄。
例如:with engine.begin() as connection: with connection.begin_nested(): connection.execute(table.insert(), {"username": "sandy"})
返回的对象是NestedTransaction
,其中包括事务方法NestedTransaction.commit()
和NestedTransaction.rollback()
;对于嵌套事务,这些方法对应于作 “RELEASE SAVEPOINT” 和 “ROLLBACK TO SAVEPOINT ”。保存点的名称是 NestedTransaction
对象的本地名称,并且是自动生成的。与任何其他Transaction
一样,NestedTransaction
可以用作上下文管理器,如上所示,它将“释放”或“回滚”对应于块内的作是否成功或引发异常。
嵌套事务需要在底层数据库中支持 SAVEPOINT,否则行为是不确定的。SAVEPOINT 通常用于在可能失败的事务中运行作,同时继续外部事务。例如:from sqlalchemy import exc with engine.begin() as connection: trans = connection.begin_nested() try: connection.execute(table.insert(), {"username": "sandy"}) trans.commit() except exc.IntegrityError: # catch for duplicate username trans.rollback() # rollback to savepoint # outer transaction continues connection.execute(...)
如果在未先调用Connection.begin_nested
Connection.begin()
或Engine.begin()
时,Connection
对象将首先 “autostart” 外部事务。这个外部事务可以使用 “commit-as-you-go” 样式提交,例如:with engine.connect() as connection: # begin() wasn't called with connection.begin_nested(): # will auto-"begin()" first connection.execute(...) # savepoint is released connection.execute(...) # explicitly commit outer transaction connection.commit() # can continue working with connection here
在 2.0 版本发生变更:Connection.begin_nested()
现在将参与 2.0 中新增的连接 “autobegin” 行为 / 1.4 中的 “future” 样式连接。
-
方法sqlalchemy.engine.Connection 中。
begin_twophase(xid:AnyNone=None)TwoPhaseTransaction ¶
开始两阶段或 XA 事务并返回事务句柄。
返回的对象是TwoPhaseTransaction
的实例, 除了Transaction 的 Transaction
,还提供了一个TwoPhaseTransaction.prepare()
方法。
参数
xid¶ – 两阶段交易 ID。如果未提供,将生成一个随机 ID。
-
方法sqlalchemy.engine.Connection 中。
close()无 ¶
关闭此连接
。
这将导致底层数据库资源(即内部引用的 DBAPI 连接)的释放。DBAPI 连接通常会恢复到生成此连接的引擎
引用的连接持有池
连接
。DBAPI 连接上存在的任何事务状态也会通过 DBAPI 连接的rollback()
方法无条件释放,而不管此连接
可能未完成的任何Transaction
对象如何。
这还具有调用Connection.rollback()
的效果 如果有任何交易。
调用Connection.close()
后,Connection
始终处于关闭状态,不允许进一步作。
-
属性sqlalchemy.engine.Connection 的 Connection。
已关闭¶
如果此连接已关闭,则返回 True。
-
方法sqlalchemy.engine.Connection 中。
commit()无 ¶
提交当前正在进行的事务。
如果已启动事务,则此方法提交当前事务。如果未启动事务,则该方法无效,假设连接处于非无效状态。
事务会自动在Connection
上开始 每当首次执行语句时,或者当Connection.begin()
方法。
注意Connection.commit()
方法仅作用于 链接到Connection
对象。 它不对 SAVEPOINT 的 SAVEPOINT,该 SAVEPOINT 本应从Connection.begin_nested()
方法;要控制 SAVEPOINT,请在
NestedTransaction
返回的Connection.begin_nested()
方法本身。
-
属性sqlalchemy.engine.Connection 的 Connection。
连接¶
由此 Connection 管理的基础 DB-API 连接。
这是一个 SQLAlchemy 连接池代理连接 该 API 具有属性_ConnectionFairy.dbapi_connection
这是指实际的驱动程序连接。
-
属性sqlalchemy.engine.Connection 的 Connection。
default_isolation_level¶
与 使用中的方言
。
此值独立于Connection.execution_options.isolation_level
和Engine.execution_options.isolation_level
执行选项,并由Dialect
在创建第一个连接时确定,方法是在发出任何其他命令之前对当前隔离级别的数据库执行 SQL 查询。
调用此访问器不会调用任何新的 SQL 查询。
-
方法sqlalchemy.engine.Connection 中。
detach()无 ¶
将底层 DB-API 连接与其连接池分离。
例如:with engine.connect() as conn: conn.detach() conn.execute(text("SET search_path TO schema1, schema2")) # work with connection # connection is fully closed (since we used "with:", can # also call .close())
此Connection
实例将保持可用。当关闭(或从如上所述的上下文管理器上下文退出)时,DB-API 连接将真正关闭,并且不会返回到其原始池。
此方法可用于将应用程序的其余部分与连接上的修改状态(例如事务隔离级别或类似级别)隔离开来。
-
方法sqlalchemy.engine.Connection 中。
exec_driver_sql(statement: str, parameters:_DBAPIAnyExecuteParamsNone=None, execution_options:CoreExecuteOptionsParameterNone=None)CursorResult[Any] ¶
直接在 DBAPI 游标上执行字符串 SQL 语句,无需任何 SQL 编译步骤。
这可用于将任何字符串直接传递给cursor.execute()
方法。
参数
结果-
例如,多个词典:conn.exec_driver_sql( "INSERT INTO table (id, value) VALUES (%(id)s, %(value)s)", [{"id": 1, "value": "v1"}, {"id": 2, "value": "v2"}], )
单个词典:conn.exec_driver_sql( "INSERT INTO table (id, value) VALUES (%(id)s, %(value)s)", dict(id=1, value="v1"), )
单元组:conn.exec_driver_sql( "INSERT INTO table (id, value) VALUES (?, ?)", (1, "v1") )
注意Connection.exec_driver_sql()
方法执行 不参与ConnectionEvents.before_execute()
和ConnectionEvents.after_execute()
事件。要拦截对Connection.exec_driver_sql() 的
调用,请使用ConnectionEvents.before_cursor_execute()
和ConnectionEvents.after_cursor_execute()
。
另请参阅
-
方法sqlalchemy.engine.Connection 中。
execute(statement: Executable, parameters:_CoreAnyExecuteParamsNone=None, *, execution_options:CoreExecuteOptionsParameterNone=None)CursorResult[Any] ¶
执行 SQL 语句结构并返回CursorResult 的 Cursor Result
中。
参数
语句¶ –
要执行的语句。这始终是一个对象,它同时位于ClauseElement
和可执行
层次结构,包括:DDL
和继承自ExecutableDDLElement
parameters¶ —— 将绑定到语句中的参数。这可以是参数名称到值的字典,也可以是字典的可变序列(例如列表)。当传递字典列表时,底层语句执行将使用 DBAPIcursor.executemany()
方法。当传递单个字典时,DBAPIcursor.execute()
方法。
execution_options¶ – 可选的执行选项字典,将与语句执行相关联。此词典可以提供 接受的选项的子集Connection.execution_options()
。
结果Result
对象。
-
方法sqlalchemy.engine.Connection 中。
execution_options(**opt: any)连接¶
为连接设置非 SQL 选项,这些选项在执行过程中生效。
此方法就地修改此Connection
;返回值是调用该方法的同一Connection
对象。请注意,这与execution_options
方法在其他对象上的行为形成对比,例如Engine.execution_options()
和Executable.execution_options()
。基本原理是,许多这样的执行选项在任何情况下都必须修改基本 DBAPI 连接的状态,因此没有可行的方法可以将此类选项的效果本地化到 “sub” 连接。
在 2.0 版更改: 这Connection.execution_options()
方法与具有此方法的其他对象相反,它会修改 就地连接,而不创建其副本。
正如在其他地方讨论的那样,Connection.execution_options()
method 接受任何任意参数,包括用户定义的名称。 给出的所有参数都可以通过多种方式使用,包括 通过使用Connection.get_execution_options()
method.请参阅以下示例Executable.execution_options()
和Engine.execution_options()
的 API 中。
SQLAlchemy 本身当前识别的关键字包括Executable.execution_options()
下列出的所有关键字,以及特定于Connection
的其他关键字。
参数compiled_cache¶ –
一个字典,当
Connection
编译子句 expression 转换为Compiled
对象。 此字典将 取代可在发动机
本身。如果设置为 None,则禁用缓存,即使引擎已配置缓存大小。
请注意,ORM 使用自己的“编译”缓存进行某些作,包括 flush作。ORM 在内部使用的缓存取代了此处指定的缓存字典。logging_token¶ –
适用于:连接
、Engine
、Executable 的 Executable
中。
在连接记录的日志消息中添加用括号括起来的指定字符串令牌,即通过create_engine.echo
标志或通过logging.getLogger("sqlalchemy.engine")
记录。这允许每个连接或每个子引擎令牌可用,这对于调试并发连接场景非常有用。
1.4.0b2 版本的新Function。isolation_level¶ –
为此的生命周期设置事务隔离级别Connection
对象。有效值包括create_engine.isolation_level
接受的字符串值 参数传递给create_engine()
的这些级别是特定于半数据库的;有关有效级别,请参阅各个 dialect 文档。
isolation level 选项通过在 DBAPI 连接上发出语句来应用隔离级别,并且必然会影响 原始 Connection 对象。隔离级别将保持为给定的设置,直到显式更改,或者当 DBAPI 连接本身被释放到连接池(即Connection.close()
方法,此时事件处理程序将在 DBAPI 连接上发出其他语句,以恢复隔离级别更改。
注意isolation_level
执行选项只能在Connection.begin()
方法之前建立 调用,以及在发出任何 SQL 语句之前,这些语句 否则会触发 “autobegin”,或者直接在调用Connection.commit()
或Connection.rollback()
的数据库无法更改正在进行的事务的隔离级别。
注意
如果Connection
无效,例如通过Connection.invalidate()
方法,或者发生断开连接错误,则isolation_level
执行选项将被隐式重置。失效后生成的新连接不会自动重新应用选定的隔离级别。no_parameters¶ –
当为True
时,如果最终的参数列表或字典完全为空,则会以cursor.execute(statement)
的形式调用游标上的语句,根本不传递参数集合。一些 DBAPI(如 psycopg2 和 mysql-python)仅在存在参数时才将百分号视为有效;此选项允许代码生成包含百分号(可能还有其他字符)的 SQL,这些 SQL 对于它是由 DBAPI 执行还是通过管道传输到稍后由命令行工具调用的脚本中是中立的。stream_results¶ –
如果可能,请向方言指示结果应该是 “streamed” 而不是预缓冲的。对于 PostgreSQL、MySQL 和 MariaDB 等后端,这表示使用“服务器端游标”,而不是客户端游标。默认情况下,其他后端(例如 Oracle Database 的后端)可能已经使用服务器端游标。
的用法Connection.execution_options.stream_results
通常与设置要批量获取的固定行数相结合,以允许数据库行的高效迭代,同时不一次将所有结果行加载到内存中;这可以在Result
对象上使用Result.yield_per()
方法,则在执行后返回新的Result
。 如果Result.yield_per()
未使用,则Connection.execution_options.stream_results
作模式将改用动态大小的缓冲区 一次缓冲行集,在每个批次上增长 基于固定的增长大小,直到可能的限制 使用Connection.execution_options.max_row_buffer
参数。
当使用 ORM 从结果中获取 ORM 映射对象时,Result.yield_per()
应始终与Connection.execution_options.stream_results
,这样 ORM 就不会一次将所有行提取到新的 ORM 对象中。
在典型使用中,Connection.execution_options.yield_per
执行 选项,这会同时设置Connection.execution_options.stream_results
和Result.yield_per()
中。Connection
和 ORMSession
在核心级别都支持此选项;后者在 使用 Yield Per 获取大型结果集。max_row_buffer¶ –
适用于:连接
、可执行文件
。 设置最大值 buffer size (缓冲区大小)Connection.execution_options.stream_results
execution 选项用于支持 Server 端的后端 游标。 如果未指定,则默认值为 1000。yield_per¶ –
适用于:连接
、可执行文件
。Integer 值,该值将设置Connection.execution_options.stream_results
执行选项并调用Result.yield_per()
自动。 允许与 在 ORM 中使用此参数时存在。
在 1.4.40 版本加入.
另请参阅
使用服务器端游标(也称为流结果)- 将服务器端游标与 Core 结合使用的背景和示例。
使用 Yield Per 获取大型结果集 - 在 ORM Querying Guide 中 描述yield_per
的 ORM 版本insertmanyvalues_page_size¶ –
适用于:连接
、发动机
。当语句使用“insertmanyvalues”模式时,要格式化为 INSERT 语句的行数,该模式是批量插入的分页形式,在使用 executemany 执行时通常用于许多后端,通常结合使用 与 RETURNING。默认值为 1000。也可以在 每个引擎使用create_engine.insertmanyvalues_page_size
参数。
2.0 版的新Function。schema_translate_map¶ –
适用于:连接
、Engine
、Executable 的 Executable
中。
将架构名称映射到架构名称的字典,该字典将应用于每个桌子
在 SQL 或 DDL 表达式元素时遇到 编译成字符串;生成的 Schema 名称将为 根据原始名称在 Map 中的存在情况进行转换。
另请参阅preserve_rowcount¶ –
布尔;当 True 时,cursor.rowcount
attribute 将在结果中无条件地记住,并且 通过CursorResult.rowcount
属性提供。 通常,仅为 UPDATE 和 DELETE 保留此属性 语句。 使用此选项,DBAPIs rowcount 值可以 对于其他类型的语句(如 INSERT 和 SELECT)进行访问, 到 DBAPI 支持这些语句的程度。 看CursorResult.rowcount
有关此属性行为的注释。
2.0.28 新版功能.
另请参阅Executable.execution_options()
Connection.get_execution_options()
ORM 执行选项 - 有关所有 ORM 特定执行选项的文档
-
方法sqlalchemy.engine.Connection 中。
get_execution_options() _ExecuteOptions ¶
获取将在执行过程中生效的非 SQL 选项。
在 1.3 版本加入.
-
方法sqlalchemy.engine.Connection 中。
get_isolation_level()Literal['SERIALIZABLE', 'REPEATABLE READ', 'READ COMMITTED', 'READ UNCOMMITTED', 'AUTOCOMMIT'] ¶
返回此连接范围内数据库上存在的当前实际隔离级别。
此属性将对数据库执行实时 SQL作,以便获得当前的隔离级别,因此返回的值是底层 DBAPI 连接上的实际级别,而不管此状态是如何设置的。这将是四种实际隔离模式之一READ UNCOMMITTED,
READ COMMITTED
,REPEATABLE READ
,SERIALIZABLE 的 SERIALIZABLE
中。它将不包括AUTOCOMMIT
隔离级别设置。第三方方言也可能具有其他隔离级别设置。
注意
此方法不会报告AUTOCOMMIT
隔离级别,这是一个独立于实际隔离级别的单独 DBAPI 设置。当AUTOCOMMIT
为 在使用中,数据库连接仍然具有“传统”隔离 mode 的 v.READ UNCOMMITTED,
READ COMMITTED,
REPEATABLE READ,
SERIALIZABLE 的 SERIALIZABLE
中。
与Connection.default_isolation_level
访问器返回 数据库。
-
方法sqlalchemy.engine.Connection 中。
get_nested_transaction()→NestedTransactionNone¶
返回当前正在进行的嵌套事务(如果有)。
在 1.4 版本加入.
-
方法sqlalchemy.engine.Connection 中。
get_transaction()→RootTransactionNone¶
返回当前正在进行的根事务(如果有)。
在 1.4 版本加入.
-
方法sqlalchemy.engine.Connection 中。
in_nested_transaction()bool ¶
如果事务正在进行,则返回 True。
-
方法sqlalchemy.engine.Connection 中。
in_transaction()bool ¶
如果事务正在进行,则返回 True。
-
属性sqlalchemy.engine.Connection 的 Connection。
信息¶
与此Connection
引用的基础 DBAPI 连接关联的信息字典,允许用户定义的数据与该连接相关联。
此处的数据将与 DBAPI 连接一起运行,包括在返回到连接池并在后续的Connection
实例中再次使用之后。
-
方法sqlalchemy.engine.Connection 中。
invalidate(exception:BaseExceptionNone=None)无 ¶
使与此Connection
关联的基础 DBAPI 连接失效。
将尝试立即关闭基础 DBAPI 连接;但是,如果此作失败,则会记录错误,但不会引发错误。然后,无论 close() 是否成功,都会丢弃该连接。
下次使用时(其中 “use” 通常是指使用Connection.execute()
方法或类似方法),此Connection
将尝试 使用Pool
作为连接源(例如“重新连接”)。
如果事务正在进行中(例如Connection.begin()
方法),当调用 Connection.invalidate()
方法时,在 DBAPI 级别,由于关闭了 DBAPI 连接,因此与此事务关联的所有状态都将丢失。联系
不允许重新连接继续进行,直到Transaction
对象结束,通过调用Transaction.rollback()
方法;在此之前,任何继续使用Connection
的尝试都将引发InvalidRequestError 的 Error
。这是为了防止应用程序意外地继续正在进行的事务作,尽管事务已因失效而丢失。Connection.invalidate()
方法 就像自动失效一样, 将在连接池级别调用PoolEvents.invalidate()
事件。
参数
exception¶——一个可选的Exception
实例,这是失效的原因。传递给事件处理程序和日志记录函数。
另请参阅
-
属性sqlalchemy.engine.Connection 的 Connection。
无效¶
如果此连接无效,则返回 True。
但是,这并不表示连接是否在池级别失效
-
方法sqlalchemy.engine.Connection 中。
rollback()无 ¶
回滚当前正在进行的事务。
如果已启动事务,则此方法回滚当前事务。如果未启动事务,则该方法无效。如果事务已启动并且连接处于无效状态,则使用此方法清除事务。
事务会自动在Connection
上开始 每当首次执行语句时,或者当Connection.begin()
方法。
注意Connection.rollback()
方法仅作用于 在链接到Connection
对象。 它不对 SAVEPOINT 的 SAVEPOINT,该 SAVEPOINT 本应从Connection.begin_nested()
方法;要控制 SAVEPOINT,请在
NestedTransaction
返回的Connection.begin_nested()
方法本身。
-
方法sqlalchemy.engine.Connection 中。
scalar(statement: Executable, parameters:_CoreSingleExecuteParamsNone=None, *, execution_options:CoreExecuteOptionsParameterNone=None)Any(任意 )
执行 SQL 语句构造并返回标量对象。
此方法是调用Result.scalar()
方法。Connection.execute()
方法。参数是等效的。
结果
一个标量 Python 值,表示返回的第一行的第一列。
-
方法sqlalchemy.engine.Connection 中。
scalars(statement: Executable, parameters:_CoreAnyExecuteParamsNone=None, *, execution_options:CoreExecuteOptionsParameterNone=None)ScalarResult[Any] ¶
执行并返回标量结果集,该结果集从每行的第一列生成标量值。
此方法等效于调用Connection.execute()
接收Result
对象,然后调用Result.scalars()
方法生成一个ScalarResult
实例。
在 1.4.24 版本加入.
-
方法sqlalchemy.engine.Connection 中。
schema_for_object(obj: HasSchemaAttr)→strNone¶
返回给定架构项的架构名称,同时考虑当前架构转换映射。
-
-
类 sqlalchemy.engine 中。CreateEnginePlugin(创建引擎插件)¶
一组钩子,旨在增强Engine
对象。CreateEnginePlugin
的目的是允许第三方 在没有 需要修改目标应用程序;相反,插件 可以将名称添加到数据库 URL 中。 目标应用程序CreateEnginePlugin
包括:
connection 和 SQL 性能工具,例如,使用 events 来跟踪签出次数和/或语句所用时间
连接插件,例如代理
将 Logger 附加到Engine
对象的基本CreateEnginePlugin
可能如下所示:import logging from sqlalchemy.engine import CreateEnginePlugin from sqlalchemy import event class LogCursorEventsPlugin(CreateEnginePlugin): def __init__(self, url, kwargs): # consume the parameter "log_cursor_logging_name" from the # URL query logging_name = url.query.get( "log_cursor_logging_name", "log_cursor" ) self.log = logging.getLogger(logging_name) def update_url(self, url): "update the URL to one that no longer includes our parameters" return url.difference_update_query(["log_cursor_logging_name"]) def engine_created(self, engine): "attach an event listener after the new Engine is constructed" event.listen(engine, "before_cursor_execute", self._log_event) def _log_event( self, conn, cursor, statement, parameters, context, executemany, ): self.log.info("Plugin logged cursor event: %s", statement)
插件使用入口点注册的方式与 dialect 类似:entry_points = { "sqlalchemy.plugins": [ "log_cursor_plugin = myapp.plugins:LogCursorEventsPlugin" ] }
使用上述名称的插件将从数据库 URL 调用,如下所示:from sqlalchemy import create_engine engine = create_engine( "mysql+pymysql://scott:tiger@localhost/test?" "plugin=log_cursor_plugin&log_cursor_logging_name=mylogger" )
plugin
URL 参数支持多个实例,因此一个 URL 可以指定多个插件;它们按照 URL 中规定的顺序加载:engine = create_engine( "mysql+pymysql://scott:tiger@localhost/test?" "plugin=plugin_one&plugin=plugin_twp&plugin=plugin_three" )
插件名称也可以直接传递给create_engine()
使用create_engine.plugins
参数:engine = create_engine( "mysql+pymysql://scott:tiger@localhost/test", plugins=["myplugin"] )
在 1.2.3 版本加入: 插件名称也可以指定为create_engine()
作为列表
插件可以使用来自URL
对象以及kwargs
字典,该字典是传递给create_engine()
的参数字典 叫。 “消耗”这些论点包括必须删除它们 当插件初始化时,这样参数就不会被传递 添加到Dialect
构造函数中,他们将在其中引发一个ArgumentError 的 ArgumentError 的 Var
错误,因为它们不被方言所知。
从 SQLAlchemy 的 1.4 版本开始,通过使用dict.pop
等方法删除值,应继续直接从kwargs
字典中使用参数。来自URL
对象的参数 应该通过实现CreateEnginePlugin.update_url()
方法,返回删除了插件特定参数的URL
的新副本:class MyPlugin(CreateEnginePlugin): def __init__(self, url, kwargs): self.my_argument_one = url.query["my_argument_one"] self.my_argument_two = url.query["my_argument_two"] self.my_argument_three = kwargs.pop("my_argument_three", None) def update_url(self, url): return url.difference_update_query( ["my_argument_one", "my_argument_two"] )
如上所示的参数将从create_engine()
调用,例如:from sqlalchemy import create_engine engine = create_engine( "mysql+pymysql://scott:tiger@localhost/test?" "plugin=myplugin&my_argument_one=foo&my_argument_two=bar", my_argument_three="bat", )
在 1.4 版本发生变更:URL
对象现在是不可变的;一个CreateEnginePlugin
的URL
应实现新添加的CreateEnginePlugin.update_url()
方法,该方法在构建插件后调用。
对于迁移,请按以下方式构建插件,检查是否存在CreateEnginePlugin.update_url()
检测正在运行的版本的方法:class MyPlugin(CreateEnginePlugin): def __init__(self, url, kwargs): if hasattr(CreateEnginePlugin, "update_url"): # detect the 1.4 API self.my_argument_one = url.query["my_argument_one"] self.my_argument_two = url.query["my_argument_two"] else: # detect the 1.3 and earlier API - mutate the # URL directly self.my_argument_one = url.query.pop("my_argument_one") self.my_argument_two = url.query.pop("my_argument_two") self.my_argument_three = kwargs.pop("my_argument_three", None) def update_url(self, url): # this method is only called in the 1.4 version return url.difference_update_query( ["my_argument_one", "my_argument_two"] )
另请参阅
URL 对象现在是不可变的 -URL
更改概述,其中还包括有关CreateEnginePlugin
的说明。
当引擎创建过程完成并生成Engine
对象,它再次通过CreateEnginePlugin.engine_created()
钩。在这个钩子中,可以对引擎进行额外的更改,最常见的是涉及事件的设置(例如,在 Core Events 中定义的事件)。-
方法sqlalchemy.engine.CreateEnginePlugin.
__init__(url: URL, kwargs: Dict[str, Any])¶
构造新的CreateEnginePlugin
。
对于每次对create_engine() 的
调用,都会单独实例化插件对象。单个 Engine 将传递给与此 URL 对应的CreateEnginePlugin.engine_created()
方法。
参数
网址¶ –URL
对象。插件可能会检查URL
中的参数。应通过返回更新的URL
来删除插件使用的参数 从CreateEnginePlugin.update_url()
方法。
在 1.4 版本发生变更:URL
对象现在是不可变的,因此CreateEnginePlugin
的URL
对象应实现CreateEnginePlugin.update_url()
方法。
kwargs¶– 传递给create_engine()
中。
-
方法sqlalchemy.engine.CreateEnginePlugin.
engine_created(engine: Engine)无 ¶
接收引擎
object 的 API 中。
该插件可能会对引擎进行其他更改,例如注册引擎或连接池事件。
-
方法sqlalchemy.engine.CreateEnginePlugin.
handle_dialect_kwargs(dialect_cls: Type[Dialect], dialect_args: Dict[str, Any])无 ¶
解析和修改 dialect kwargs
-
方法sqlalchemy.engine.CreateEnginePlugin.
handle_pool_kwargs(pool_cls: Type[Pool], pool_args: Dict[str, Any])无 ¶
解析和修改 pool kwargs
-
方法sqlalchemy.engine.CreateEnginePlugin.
update_url(url: URL)URL ¶
更新URL
。
应返回新URL
。 此方法为 通常用于使用 必须删除的URL
,因为它们不会被 被方言识别。 这URL.difference_update_query()
方法可用 以删除这些参数。 请参阅文档字符串CreateEnginePlugin
示例。
在 1.4 版本加入.
-
类 sqlalchemy.engine 中。引擎¶ -
Engine
对象使用create_engine()
函数。
成员
begin(), clear_compiled_cache(), connect(), dispose(), 驱动程序, 引擎, execution_options(), get_execution_options(), 名称, raw_connection(), update_execution_options()
类签名
类sqlalchemy.engine.Engine
(sqlalchemy.engine.interfaces.ConnectionEventsTarget
,sqlalchemy.log.Identified
,sqlalchemy.inspection.Inspectable
)-
方法sqlalchemy.engine.Engine 中。
begin()Iterator[连接] ¶
返回传递Connection
的上下文管理器 并建立了交易
。
例如:with engine.begin() as conn: conn.execute(text("insert into table (x, y, z) values (1, 2, 3)")) conn.execute(text("my_special_procedure(5)"))
作成功后,交易
已提交。 如果引发错误,则 Transaction
将回滚。
-
方法sqlalchemy.engine.Engine 中。
clear_compiled_cache()无 ¶
清除与方言关联的已编译缓存。
这仅适用于通过create_engine.query_cache_size
parameter 建立的内置缓存。 它不会影响通过Connection.execution_options.compiled_cache
参数。
在 1.4 版本加入.
-
方法sqlalchemy.engine.Engine 中。
connect()连接 ¶
返回新的Connection
对象。Connection
充当 Python 上下文管理器,因此此方法的典型用法如下所示:with engine.connect() as connection: connection.execute(text("insert into table values ('foo')")) connection.commit()
在上面,在块完成后,连接被 “关闭” ,其底层 DBAPI 资源被返回到连接池。这还具有回滚显式开始或通过 autobegin 开始的任何事务的效果,并且如果已启动且仍在进行中,则会发出ConnectionEvents.rollback()
事件。
另请参阅
-
方法sqlalchemy.engine.Engine 中。
dispose(close: bool = True)无 ¶
释放 this 使用的连接池发动机
。
在处理旧连接池后,将立即创建一个新的连接池。通过关闭该池中所有当前签入的连接来主动处理前一个连接池,或者通过被动地丢失对它的引用但不关闭任何连接来释放。后一种策略更适合分叉 Python 进程中的初始化器。
参数
关闭¶ –
如果保留为默认值True
,则具有完全关闭当前签入的所有 数据库连接。 仍处于签出状态的连接 不会关闭,但它们将不再与此引擎
相关联, 因此,当它们单独关闭时,最终 与他们关联的游泳池
将被垃圾回收,如果在入住时尚未关闭,它们将被完全关闭。
如果设置为False
,则取消引用前一个连接池,否则不会以任何方式触及。
1.4.33 版本中的新功能: 添加了Engine.dispose.close
参数以允许替换子节点中的连接池 进程而不干扰父级使用的连接 过程。
-
属性sqlalchemy.engine.Engine 的
引擎¶
返回此Engine
。
用于接受Connection
/Engine
对象。
-
方法sqlalchemy.engine.Engine 中。
execution_options(**opt: Any)OptionEngine ¶
返回将提供Connection
对象。
返回的Engine
仍与原始 Engine 关联Engine 的 URL
中,它共享相同的连接池和其他状态:
新引擎
使用的池
是 同一实例。Engine.dispose()
method 将替换 父引擎的连接池实例 就像这个一样。
日志记录配置和logging_name是从父级复制的发动机
。
Engine.execution_options()
方法的目的是实现多个Engine
对象引用相同的连接池,但存在差异 by 选项,这些选项会影响每个 发动机。 一个这样的例子是分成单独的 “reader” 和 “writer”Engine
实例,其中一个发动机
配置了较低的隔离级别设置,甚至使用 “autocommit” 禁用了事务。此配置的一个示例是在维护单个引擎的多个隔离级别中。
另一个示例是使用事件使用的自定义选项shard_id
来更改数据库连接上的当前架构:from sqlalchemy import event from sqlalchemy.engine import Engine primary_engine = create_engine("mysql+mysqldb://") shard1 = primary_engine.execution_options(shard_id="shard1") shard2 = primary_engine.execution_options(shard_id="shard2") shards = {"default": "base", "shard_1": "db1", "shard_2": "db2"} @event.listens_for(Engine, "before_cursor_execute") def _switch_shard(conn, cursor, stmt, params, context, executemany): shard_id = conn.get_execution_options().get("shard_id", "default") current_shard = conn.info.get("current_shard", None) if current_shard != shard_id: cursor.execute("use %s" % shards[shard_id]) conn.info["current_shard"] = shard_id
上面的配方说明了两个Engine
对象,每个对象都将用作Connection
对象的工厂 存在预先建立的 “shard_id” 执行选项。一个ConnectionEvents.before_cursor_execute()
然后,事件处理程序解释此执行选项以发出 MySQLuse
语句 在语句执行之前切换数据库,同时 使用Connection.info
字典。
另请参阅
Connection.execution_options()
- 更新执行选项 在Connection
对象上。
-
方法sqlalchemy.engine.Engine 中。
get_execution_options() _ExecuteOptions ¶
获取将在执行过程中生效的非 SQL 选项。
-
方法sqlalchemy.engine.Engine 中。
raw_connection()PoolProxiedConnection ¶
从连接池中返回 “原始” DBAPI 连接。
返回的对象是正在使用的基础驱动程序使用的 DBAPI 连接对象的代理版本。该对象将具有与实际 DBAPI 连接相同的行为,不同之处在于其close()
方法将导致连接返回到池中,而不是真正关闭。
此方法为 特殊情况,当 API 由连接
不需要。 当Connection
对象已存在时,可以使用Connection.connection
访问器使用 DBAPI 连接。
-
方法sqlalchemy.engine.Engine 中。
update_execution_options(**opt: any)无 ¶
更新此Engine
的默认 execution_options 字典。
opt 中给定的键/值将添加到将用于所有连接的默认执行选项中。此字典的初始内容可以通过execution_options
参数发送到create_engine()
。
-
-
类 sqlalchemy.engine 中。ExceptionContext¶
封装有关正在进行的错误条件的信息。
成员
chained_exception、连接、游标、方言、引擎、execution_context、invalidate_pool_on_disconnect、is_disconnect、is_pre_ping、original_exception、参数、sqlalchemy_exception、语句
此对象的存在只是为了传递给DialectEvents.handle_error()
事件,支持可以在不向后不兼容的情况下扩展的接口。-
属性sqlalchemy.engine.ExceptionContext.
chained_exception:BaseExceptionNone¶
异常链中上一个处理程序返回的异常(如果有)。
如果存在,则此异常将是 SQLAlchemy 最终引发的异常,除非后续处理程序替换它。
可以是 None。
-
attributesqlalchemy.engine.ExceptionContext.
connection:ConnectionNone¶
异常期间正在使用的 Connection
。
此成员存在,除非首次连接时出现故障。
-
attributesqlalchemy.engine.ExceptionContext.
cursor:D BAPICursorNone¶
DBAPI 游标对象。
可以是 None。
-
attributesqlalchemy.engine.ExceptionContext.
dialect: 方言¶
正在使用的Dialect
。
此成员存在于事件钩子的所有调用中。
2.0 版的新Function。
-
属性sqlalchemy.engine.ExceptionContext.
engine:EngineNone¶
异常期间正在使用的Engine
。
此成员在所有情况下都存在,但在连接池 “pre-ping” 进程中处理错误时除外。
-
属性sqlalchemy.engine.ExceptionContext.
execution_context:ExecutionContextNone¶
与正在进行的执行作对应的ExecutionContext
。
这适用于语句执行作,但不适用于事务开始/结束等作。在ExecutionContext
之前引发异常时,它也不存在 可以构建。
请注意,ExceptionContext.statement
和ExceptionContext.parameters
成员可能表示与ExecutionContext
不同的值, 可能在ConnectionEvents.before_cursor_execute()
event 或类似作修改了要发送的语句/参数。
可以是 None。
-
属性sqlalchemy.engine.ExceptionContext.
invalidate_pool_on_disconnect: bool¶
表示当 “disconnect” 条件生效时,是否应使池中的所有连接失效。
在DialectEvents.handle_error()
事件将产生这样的效果 池中的完整连接集合不会 在断开连接期间失效;只有当前连接,即 error 的主题实际上将失效。
此标志的用途是自定义断开连接处理方案,其中将根据其他条件甚至基于每个连接执行池中其他连接的失效。
-
属性sqlalchemy.engine.ExceptionContext.
is_disconnect:bool¶
表示发生的异常是否表示 “断开连接” 情况。
此标志在DialectEvents.handle_error()
处理程序。
SQLAlchemy 将遵循此标志,以确定是否应随后使连接失效。也就是说,通过分配给此标志,可以通过更改此标志来调用或阻止导致连接和池失效的“断开连接”事件。
注意
使用pre_pingcreate_engine.pool_pre_ping
参数不会 在确定 “ping” 是否返回 false 之前,请先咨询此事件。 而不是收到未处理的错误。 对于此使用案例, 可以使用基于 engine_connect() 的 legacy 配方。未来的 API 允许在所有功能中更全面地自定义 “断开连接” 检测机制。
-
属性sqlalchemy.engine.ExceptionContext.
is_pre_ping: bool¶
指示此错误是否发生在create_engine.pool_pre_ping
设置为没错
。在此模式下,ExceptionContext.engine
属性将为None
。 正在使用的方言可通过ExceptionContext.dialect
属性。
2.0.5 新版功能.
-
属性sqlalchemy.engine.ExceptionContext.
original_exception: BaseException¶
捕获的异常对象。
此成员始终存在。
-
属性sqlalchemy.engine.ExceptionContext.
参数:_DBAPIAnyExecuteParamsNone¶
直接发送到 DBAPI 的参数集合。
可以是 None。
-
属性sqlalchemy.engine.ExceptionContext.
sqlalchemy_exception:StatementErrorNone¶ sqlalchemy.exc.StatementError
包装原始错误,如果事件未规避异常处理,则会引发该错误。
可能是 None,因为并非所有异常类型都由 SQLAlchemy 包装。对于子类化 dbapi 的 Error 类的 DBAPI 级异常,此字段将始终存在。
-
attributesqlalchemy.engine.ExceptionContext.
语句:strNone¶
String SQL 语句。
可以是 None。
-
-
类 sqlalchemy.engine 中。NestedTransaction 交易¶
表示 'nested' 或 SAVEPOINT 事务。NestedTransaction
对象是通过调用Connection.begin_nested()
方法连接
。
使用NestedTransaction
时,“begin” / “commit” / “rollback” 的语义如下:
“begin”作对应于 “BEGIN SAVEPOINT” 命令,其中 savepoint 被赋予一个显式名称,该名称是此对象状态的一部分。NestedTransaction.commit()
方法对应于 “RELEASE SAVEPOINT”作,使用与此NestedTransaction
关联的保存点标识符。NestedTransaction.rollback()
方法对应于“ROLLBACK TO SAVEPOINT”作,使用与此NestedTransaction
关联的保存点标识符。
根据 savepoint 模拟外部事务的语义的基本原理,以便代码可以以不可知的方式处理 “savepoint” 事务和 “outer” 事务。
另请参阅
使用 SAVEPOINT - SAVEPOINT API 的 ORM 版本。-
方法sqlalchemy.engine.NestedTransaction.
close()None ¶
继承自Transaction
的Transaction.close()
方法
Close thisTransaction
(关闭此交易)。
如果此事务是 begin/commit 嵌套中的基本事务,则该事务将 rollback() 。否则,该方法返回。
这用于取消 Transaction 而不影响封闭事务的范围。
-
方法sqlalchemy.engine.NestedTransaction.
commit()无 ¶
继承自Transaction
的Transaction.commit()
方法
提交此事务
。
此实现可能因使用的事务类型而异:
对于简单的数据库事务(例如RootTransaction
),它对应于 COMMIT.
对于NestedTransaction
,它对应于“RELEASE SAVEPOINT”作。
对于TwoPhaseTransaction
,可以使用特定于 DBAPI 的方法来处理两阶段事务。
-
方法sqlalchemy.engine.NestedTransaction.
rollback(None ¶
继承自Transaction
的Transaction.rollback()
方法
回滚此Transaction
。
此实现可能因使用的事务类型而异:
对于简单的数据库事务(例如RootTransaction
),它对应于 ROLLBACK。
对于NestedTransaction
,它对应于“ROLLBACK TO SAVEPOINT”作。
对于TwoPhaseTransaction
,可以使用特定于 DBAPI 的方法来处理两阶段事务。
-
类 sqlalchemy.engine 中。RootTransaction 交易¶
表示Connection
上的 “root” 事务。
这对应于Connection
的当前 “BEGIN/COMMIT/ROLLBACK”。RootTransaction
通过调用Connection.begin()
方法创建,并在其整个活动 span 内保持与Connection
的关联。当前正在使用的RootTransaction
可以通过Connection.get_transaction
的连接
。
在 2.0 风格的使用中,Connection
还采用了 “autobegin” 行为,它将创建一个新的RootTransaction
每当使用处于非事务状态的连接在 DBAPI 连接上发出命令时。2.0 样式中RootTransaction
使用的范围可以使用Connection.commit()
和Connection.rollback()
方法。-
方法sqlalchemy.engine.RootTransaction.
close()None ¶
继承自Transaction
的Transaction.close()
方法
Close thisTransaction
(关闭此交易)。
如果此事务是 begin/commit 嵌套中的基本事务,则该事务将 rollback() 。否则,该方法返回。
这用于取消 Transaction 而不影响封闭事务的范围。
-
方法sqlalchemy.engine.RootTransaction.
commit()无 ¶
继承自Transaction
的Transaction.commit()
方法
提交此事务
。
此实现可能因使用的事务类型而异:
对于简单的数据库事务(例如RootTransaction
),它对应于 COMMIT.
对于NestedTransaction
,它对应于“RELEASE SAVEPOINT”作。
对于TwoPhaseTransaction
,可以使用特定于 DBAPI 的方法来处理两阶段事务。
-
方法sqlalchemy.engine.RootTransaction.
rollback(None ¶
继承自Transaction
的Transaction.rollback()
方法
回滚此Transaction
。
此实现可能因使用的事务类型而异:
对于简单的数据库事务(例如RootTransaction
),它对应于 ROLLBACK。
对于NestedTransaction
,它对应于“ROLLBACK TO SAVEPOINT”作。
对于TwoPhaseTransaction
,可以使用特定于 DBAPI 的方法来处理两阶段事务。
-
-
类 sqlalchemy.engine 中。交易¶
表示正在进行的数据库事务。Transaction
对象是通过调用连接
:from sqlalchemy import create_engine engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test") connection = engine.connect() trans = connection.begin() connection.execute(text("insert into x (a, b) values (1, 2)")) trans.commit()
该对象提供rollback()
和commit()
方法来控制事务边界。 它 还实现了一个 Context Manager 接口,以便 Pythonwith
语句可以与Connection.begin()
方法:with connection.begin(): connection.execute(text("insert into x (a, b) values (1, 2)"))
Transaction 对象不是线程安全的。
类签名
类sqlalchemy.engine.Transaction
()sqlalchemy.engine.util.TransactionalContext
-
方法sqlalchemy.engine.Transaction.
close()None ¶
Close thisTransaction
(关闭此交易)。
如果此事务是 begin/commit 嵌套中的基本事务,则该事务将 rollback() 。否则,该方法返回。
这用于取消 Transaction 而不影响封闭事务的范围。
-
方法sqlalchemy.engine.Transaction.
commit()无 ¶
提交此事务
。
此实现可能因使用的事务类型而异:
对于简单的数据库事务(例如RootTransaction
),它对应于 COMMIT.
对于NestedTransaction
,它对应于“RELEASE SAVEPOINT”作。
对于TwoPhaseTransaction
,可以使用特定于 DBAPI 的方法来处理两阶段事务。
-
方法sqlalchemy.engine.Transaction.
rollback(None ¶
回滚此Transaction
。
此实现可能因使用的事务类型而异:
对于简单的数据库事务(例如RootTransaction
),它对应于 ROLLBACK。
对于NestedTransaction
,它对应于“ROLLBACK TO SAVEPOINT”作。
对于TwoPhaseTransaction
,可以使用特定于 DBAPI 的方法来处理两阶段事务。
-
-
类 sqlalchemy.engine 中。TwoPhaseTransaction 交易¶
表示两阶段交易。
可以使用Connection.begin_twophase()
方法获取新的TwoPhaseTransaction
对象。
界面与Transaction
相同 添加了Prepare()
方法。-
方法sqlalchemy.engine.TwoPhaseTransaction.
close()None ¶
继承自Transaction
的Transaction.close()
方法
Close thisTransaction
(关闭此交易)。
如果此事务是 begin/commit 嵌套中的基本事务,则该事务将 rollback() 。否则,该方法返回。
这用于取消 Transaction 而不影响封闭事务的范围。
-
方法sqlalchemy.engine.TwoPhaseTransaction.
commit()无 ¶
继承自Transaction
的Transaction.commit()
方法
提交此事务
。
此实现可能因使用的事务类型而异:
对于简单的数据库事务(例如RootTransaction
),它对应于 COMMIT.
对于NestedTransaction
,它对应于“RELEASE SAVEPOINT”作。
对于TwoPhaseTransaction
,可以使用特定于 DBAPI 的方法来处理两阶段事务。
-
方法sqlalchemy.engine.TwoPhaseTransaction.
prepare()无 ¶
准备这个TwoPhaseTransaction
。
在 PREPARE 之后,可以提交事务。
-
方法sqlalchemy.engine.TwoPhaseTransaction.
rollback(None ¶
继承自Transaction
的Transaction.rollback()
方法
回滚此Transaction
。
此实现可能因使用的事务类型而异:
对于简单的数据库事务(例如RootTransaction
),它对应于 ROLLBACK。
对于NestedTransaction
,它对应于“ROLLBACK TO SAVEPOINT”作。
对于TwoPhaseTransaction
,可以使用特定于 DBAPI 的方法来处理两阶段事务。
-
结果集 API¶
对象名称 |
描述 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
-
类 sqlalchemy.engine 中。ChunkedIteratorResult(ChunkedIterator结果)¶
一个IteratorResult
,它从生成迭代器的可调用对象工作。
给定的chunks
参数是一个函数,它为每个 chunk 提供要返回的行数,或者所有行为None
。然后,该函数应返回一个未使用的列表迭代器,每个列表具有请求的大小。
该函数可以随时再次调用,在这种情况下,它应该从相同的结果集继续,但根据给定调整块大小。
在 1.4 版本加入.
成员-
方法sqlalchemy.engine.ChunkedIteratorResult.
yield_per(num: int)Self ¶
配置行获取策略以一次获取num
行。
这会影响迭代 result 对象,或者使用诸如Result.fetchone()
一次返回一行。来自底层游标或其他数据源的数据将在内存中缓冲到这么多行,然后缓冲的集合将一次产生一行或请求多少行。每次清除缓冲区时,它都会刷新到这么多行,如果剩余的行数更少,则刷新为剩余的行数。Result.yield_per()
方法通常用于 与Connection.execution_options.stream_results
execution 选项,这将允许正在使用的数据库 dialect 进行 使用服务器端游标(如果 DBAPI 支持特定的“服务器 side cursor“ 模式与其默认作模式分开。
提示
考虑使用Connection.execution_options.yield_per
execution 选项,该选项将同时设置Connection.execution_options.stream_results
确保使用服务器端游标,以及自动 调用Result.yield_per()
方法以立即建立固定的行缓冲区大小。
这Connection.execution_options.yield_per
execution 选项可用于 ORM作,其中 面向会话
的用法,如 使用 Yield Per 获取大型结果集。与Connection
配合使用的仅核心版本是 SQLAlchemy 1.4.40 的新版本。
在 1.4 版本加入.
参数
num¶ – 每次重新填充缓冲区时要获取的行数。如果设置为小于 1 的值,则获取下一个缓冲区的所有行。
-
-
类 sqlalchemy.engine 中。光标结果(CursorResult)¶
表示 DBAPI 游标中的状态的 Result。
在 1.4 版本发生变更:CursorResult 的
class 替换了之前的ResultProxy
接口。此类基于Result
调用 API,该 API 为 SQLAlchemy Core 和 SQLAlchemy ORM 提供更新的使用模型和调用门面。
通过Row
类返回数据库行,该类在 DBAPI 返回的原始数据之上提供其他 API 功能和行为。通过使用过滤器,例如Result.scalars()
方法,则可能还会返回其他类型的对象。
另请参阅
使用 SELECT 语句 - 用于访问的介绍性材料CursorResult
和Row
对象。
成员
all(), close(), columns(), fetchall(), fetchmany(), fetchone(), first(), freeze(), inserted_primary_key, inserted_primary_key_rows, is_insert, keys(), last_inserted_params(), last_updated_params()、lastrow_has_defaults()、lastrowid、mappings()、merge()、one()、one_or_none()、partitions()、postfetch_cols()、prefetch_cols()、returned_defaults、returned_defaults_rows、returns_rows、行数、标量()、scalar_one()、scalar_one_or_none()、标量()、splice_horizontally()、splice_vertically()、supports_sane_multi_rowcount()、supports_sane_rowcount()、t、元组()、unique(), yield_per()-
方法sqlalchemy.engine.CursorResult.
all()Sequence[Row[_TP]]¶
继承自Result
的Result.all()
方法
返回序列中的所有行。
调用后关闭结果集。后续调用将返回空序列。
在 1.4 版本加入.
结果Row
对象的序列。
另请参阅
使用服务器端游标(又名流结果) - 如何在不完全在 python 中加载大型结果集的情况式传输大型结果集。
-
方法sqlalchemy.engine.CursorResult.
close()Any ¶
关闭此CursorResult
。
这将关闭与语句执行对应的底层 DBAPI 游标(如果仍然存在)。请注意,当CursorResult
耗尽所有可用行。CursorResult.close()
为 通常是一种可选方法,除非在丢弃CursorResult
仍有其他行等待提取。
调用此方法后,调用 fetch 方法不再有效,这将引发ResourceClosedError
在后续使用时。
另请参阅
-
methodsqlalchemy.engine.CursorResult.
columns(*col_expressions: _KeyIndexType)Self ¶
继承自Result
的Result.columns()
方法
建立应在每行中返回的列。
此方法可用于限制返回的列以及对它们重新排序。给定的表达式列表通常是一系列整数或字符串键名称。它们也可能是对应于给定语句构造的适当ColumnElement
对象。
在 2.0 版更改: 由于 1.4 中的一个 bug,Result.columns()
方法的行为不正确 其中,调用只有一个索引的方法会导致Result
对象生成标量值,而不是Row
对象。 在版本 2.0 中,此行为 已更正,因此调用 具有单个索引的Result.columns()
将生成一个Result
对象,该对象继续生成Row
对象,其中仅包含单个列。
例如:statement = select(table.c.x, table.c.y, table.c.z) result = connection.execute(statement) for z, y in result.columns("z", "y"): ...
从语句本身使用列对象的示例:for z, y in result.columns( statement.selected_columns.c.z, statement.selected_columns.c.y ): ...
在 1.4 版本加入.
参数
*col_expressions¶ – 表示要返回的列。 元素 可以是整数行索引、字符串列名称或适当的ColumnElement
对象。
结果
thisResult
对象。
-
方法sqlalchemy.engine.CursorResult.
fetchall()序列[Row[_TP]] ¶
继承自Result
的Result.fetchall()
方法Result.all()
方法的同义词。
-
方法sqlalchemy.engine.CursorResult.
fetchmany(size:intNone=None)Sequence[Row[_TP]]¶
继承自Result
的Result.fetchmany()
方法
获取许多行。
当所有行都用完时,返回一个空序列。
提供此方法是为了向后兼容 SQLAlchemy 1.x.x。
要获取组中的行,请使用Result.partitions()
方法。
结果Row
对象的序列。
另请参阅
-
methodsqlalchemy.engine.CursorResult.
fetchone()→Row[_TP]None¶
继承自Result
的Result.fetchone()
方法
获取一行。
当所有行都用完时,返回 None。
提供此方法是为了向后兼容 SQLAlchemy 1.x.x。
要仅获取结果的第一行,请使用Result.first()
方法。要遍历所有行,请直接遍历Result
对象。
结果Row
对象(如果未应用过滤器),如果没有剩余行,则为 None
。
-
methodsqlalchemy.engine.CursorResult.
first()→Row[_TP]无¶
继承自Result
的Result.first()
方法
获取第一行,如果不存在行,则为 None
。
关闭结果集并丢弃剩余行。
注意
默认情况下,此方法返回一行,例如 tuple。 要只返回一个标量值,即第一个 列,请使用Result.scalar()
方法,或者将Result.scalars()
和Result.first() 的 Result.first()
中。
此外,与传统 ORM 的行为相比Query.first()
方法,则对 调用的 SQL 查询来生成此结果
;对于在生成行之前在内存中缓冲结果的 DBAPI 驱动程序,所有行都将发送到 Python 进程,并且除第一行之外的所有行都将被丢弃。
结果一个 Row
对象,如果没有剩余行,则为 None。
-
方法sqlalchemy.engine.CursorResult.
freeze()FrozenResult[_TP] ¶
继承自Result
的Result.freeze()
方法
返回一个可调用对象,该对象将生成此调用时的结果
。
返回的可调用对象是FrozenResult 的 Froz。
这用于结果集缓存。当结果未使用时,必须在结果上调用该方法,并且调用该方法将完全使用结果。当FrozenResult
从缓存中检索,则可以调用任意次数,其中 它每次都会针对其存储的行集生成一个新的Result
对象。
另请参阅
Re-Executing Statements - 在 ORM 中实现结果集缓存的示例用法。
-
属性sqlalchemy.engine.CursorResult.
inserted_primary_key¶
返回刚刚插入的行的主键。
返回值是一个Row
对象,表示 主键值的命名元组,其顺序为 主键列在源中配置表
。
在 1.4.8 版本发生变更: - 该CursorResult.inserted_primary_key
value 现在是通过Row
类命名的元组,而不是普通元组。
此访问器仅适用于单行insert()
未明确指定Insert.returning()
的对多行插入的支持虽然尚不适用于大多数后端,但可以使用CursorResult.inserted_primary_key_rows
访问器进行访问。
请注意,指定 server_default 子句的主键列或 否则,它们不符合 “autoincrement” 列的条件(请参阅Column
)并且是使用数据库端默认值生成的,将在此列表中显示为None
,除非后端支持 “returning” 并且在启用 “implicit returning” 的情况下执行 insert 语句。
如果执行的语句不是已编译的表达式构造或不是 insert() 构造,则引发InvalidRequestError
。
-
属性sqlalchemy.engine.CursorResult.
inserted_primary_key_rows¶
返回CursorResult.inserted_primary_key
作为列表中包含的行;某些方言可能支持 多行形式。
注意
如下所示,在当前的 SQLAlchemy 版本中,此 accessor 仅在CursorResult.inserted_primary_key
使用 psycopg2 方言。未来的版本希望将此功能推广到更多的方言。
添加此访问器是为了支持提供当前由 Psycopg2 快速执行帮助程序实现的功能的方言 功能,目前只有 psycopg2 dialect,它提供一次插入许多行,同时仍然保留能够返回服务器生成的主键值的行为。
当使用 psycopg2 方言或其他可能支持的方言时 即将发布的版本中的 “fast executemany” 样式插入:当在将行列表作为第二个参数传递给Connection.execute()
时调用 INSERT 语句时,此访问器将提供一个行列表,其中每行都包含 INSERTed 的每一行的主键值。
当使用尚不支持的所有其他方言/后端时 此功能:此访问器仅对单行 INSERT 有用 语句,并返回与CursorResult.inserted_primary_key
在 single-element 列表。当 INSERT 语句在 与要 INSERT 的行列表结合使用时,该列表将包含 在语句中插入的每一行一行,但它将包含对于
任何服务器生成的值,无。
SQLAlchemy 的未来版本将进一步推广 psycopg2 的“快速执行帮助程序”功能以适应其他方言,从而允许该访问器具有更普遍的用途。
在 1.4 版本加入.
-
属性sqlalchemy.engine.CursorResult.
is_insert¶
如果此CursorResult
是结果,则为 True 的执行表达式语言编译insert()
结构。
当 True 时,这意味着inserted_primary_key
属性是可访问的,前提是该语句不包含用户定义的 “returning” 结构。
-
方法sqlalchemy.engine.CursorResult.
keys()RMKeyView ¶
继承自sqlalchemy.engine._WithKeys.keys
sqlalchemy.engine._WithKeys
的方法
返回一个可迭代视图,该视图产生将由每个Row
表示的字符串键。
键可以表示 core 语句返回的列的标签或 orm 执行返回的 orm 类的名称。
还可以使用 Python 测试视图的密钥包含in
运算符,该运算符将测试视图中表示的字符串键以及备用键(如 Column 对象)。
在 1.4 版本发生变更: 返回一个键视图对象,而不是一个普通的列表。
-
方法sqlalchemy.engine.CursorResult.
last_inserted_params()¶
返回此执行中插入的参数的集合。
如果执行的语句不是已编译的表达式构造或不是 insert() 构造,则引发InvalidRequestError
。
-
方法sqlalchemy.engine.CursorResult.
last_updated_params()¶
返回此执行中更新的参数的集合。
如果执行的语句不是已编译的表达式构造或不是 update() 构造,则引发InvalidRequestError
。
-
方法sqlalchemy.engine.CursorResult.
lastrow_has_defaults()¶
从底层返回lastrow_has_defaults()
ExecutionContext 的 ExecutionContext
中。
有关详细信息,请参阅ExecutionContext
。
-
属性sqlalchemy.engine.CursorResult.
lastrowid¶
返回 DBAPI 游标上的 'lastrowid' 访问器。
这是一种特定于 DBAPI 的方法,仅适用于支持它的后端,适用于适当的语句。它的行为在后端之间不一致。
在以下情况下,通常不需要使用此方法 使用 insert() 表达式结构;这CursorResult.inserted_primary_key
属性为新插入的行提供主键值的元组,而不考虑数据库后端。
-
方法sqlalchemy.engine.CursorResult.
mappings()MappingResult ¶
继承自Result
的Result.mappings()
方法
将 mappings 筛选器应用于返回的行,返回MappingResult 的 MappingResult
中。
应用此过滤器后,fetching rows 将返回RowMapping
对象而不是Row
对象。
在 1.4 版本加入.
结果
引用此Result
对象的新MappingResult
筛选对象。
-
methodsqlalchemy.engine.CursorResult.
merge(*others: Result[Any])MergedResult[Any] ¶
将此Result
与其他兼容的 Result 对象合并。
返回的对象是MergedResult
的实例,它将由给定结果对象的迭代器组成。
新结果将使用此 result 对象中的元数据。后续结果对象必须针对一组相同的结果/游标元数据,否则行为未定义。
-
方法sqlalchemy.engine.CursorResult.
one()行[_TP] ¶
继承自Result
的Result.one()
方法
只返回一行或引发异常。
如果结果不返回任何行,则引发NoResultFound
,如果返回多行,则引发MultipleResultsFound
。
注意
默认情况下,此方法返回一行,例如 tuple。 要只返回一个标量值,即第一个 列,请使用Result.scalar_one()
方法或组合Result.scalars()
和Result.one() 的 Result.one()
中。
在 1.4 版本加入.
结果
第一行
。
提升:
-
方法sqlalchemy.engine.CursorResult.
one_or_none()→Row[_TP]None¶
继承自Result
的Result.one_or_none()
方法
最多返回一个结果或引发异常。
如果结果没有行,则返回None
。引发MultipleResultsFound
如果返回多行。
在 1.4 版本加入.
结果
第一行
或None
(无行)如果没有可用行。
提升:
-
方法sqlalchemy.engine.CursorResult.
partitions(size:intNone=None)Iterator[Sequence[Row[_TP]]]¶
继承自Result
的Result.partitions()
方法
遍历给定大小的行的子列表。
每个列表的大小都与给定的大小相同,但要生成的最后一个列表除外,该列表可能具有少量行数。不会产生空列表。
当迭代器被完全消耗时,result 对象会自动关闭。
请注意,后端驱动程序通常会缓冲整个结果 除非Connection.execution_options.stream_results
execution 选项表示驱动程序不应预先缓冲结果(如果可能)。并非所有驱动程序都支持此选项,对于不支持此选项的驱动程序,此选项将被静默忽略。
当使用 ORM 时,Result.partitions()
方法 从内存的角度来看,当 结合使用 yield_per执行选项,它指示 DBAPI 驱动程序使用服务器端游标(如果可用),并指示 ORM 加载内部一次只从结果构建一定数量的 ORM 对象,然后再产生它们。
在 1.4 版本加入.
参数
size¶ —— 表示生成的每个列表中存在的最大行数。如果为 None,则使用Result.yield_per()
方法设置的值(如果已调用)或Connection.execution_options.yield_per
execution 选项,这在这方面是等效的。 如果 yield_per未设置,它会使用Result.fetchmany()
默认值,它可能是特定于后端的,并且没有明确定义。
结果
列表的迭代器
-
方法sqlalchemy.engine.CursorResult.
postfetch_cols()¶
从底层返回postfetch_cols()
ExecutionContext 的 ExecutionContext
中。
有关详细信息,请参阅ExecutionContext
。
如果执行的语句不是已编译的表达式构造,或者不是 insert() 或 update() 构造,则引发InvalidRequestError
。
-
方法sqlalchemy.engine.CursorResult.
prefetch_cols()¶
从底层返回prefetch_cols()
ExecutionContext 的 ExecutionContext
中。
有关详细信息,请参阅ExecutionContext
。
如果执行的语句不是已编译的表达式构造,或者不是 insert() 或 update() 构造,则引发InvalidRequestError
。
-
属性sqlalchemy.engine.CursorResult.
returned_defaults¶
返回使用ValuesBase.return_defaults()
功能获取的默认列的值。
该值是Row
或None
的实例 如果未使用ValuesBase.return_defaults()
或后端不支持 RETURNING。
另请参阅ValuesBase.return_defaults()
-
属性sqlalchemy.engine.CursorResult.
returned_defaults_rows¶
返回一个行列表,每行都包含使用ValuesBase.return_defaults()
功能获取的默认列的值。
返回值是Row
对象的列表。
在 1.4 版本加入.
-
属性sqlalchemy.engine.CursorResult.
returns_rows¶
如果此CursorResult
返回零行或多行,则为 True。
即,如果调用方法CursorResult.fetchone()
中,则CursorResult.fetchmany()
CursorResult.fetchall()的 Cursor Result.fetchall() 的 Cursor Result.fetchall()
中。
总体而言,CursorResult.returns_rows
的值应该 始终是 DBAPI 游标是否具有.description
属性,指示存在结果列, 请注意,返回零行的游标仍然具有.description
(如果发出了返回行的语句)。
对于针对 SELECT 语句的所有结果,以及使用 RETURNING 的 DML 语句 INSERT/UPDATE/DELETE,此属性应为 True。对于未使用 RETURNING 的 INSERT/UPDATE/DELETE 语句,该值通常为 False,但是存在一些特定于方言的例外情况,例如,当使用 MSSQL / pyodbc 方言时,会内联发出 SELECT 以检索插入的主键值。
-
attribute rowcount(属性sqlalchemy.engine.CursorResult.
rowcount)¶
返回此结果的 'rowcount'。
'rowcount' 的主要目的是报告与执行一次的 UPDATE 或 DELETE 语句的 WHERE 标准匹配的行数(即对于单个参数集),然后将其与预期更新或删除的行数进行比较,作为断言数据完整性的一种手段。
此属性在游标关闭之前从 DBAPI 的cursor.rowcount
属性传输,以支持在游标关闭后不提供此值的 DBAPI。某些 DBAPI 可能为其他类型的语句(如 INSERT 和 SELECT 语句)提供有意义的值。为了检索cursor.rowcount
对于这些语句,请将Connection.execution_options.preserve_rowcount
execution 选项设置为 True,这将导致cursor.rowcount
值,以便在返回任何结果之前无条件地记住 或游标已关闭,而不管语句类型如何。
对于 DBAPI 不支持特定类型的语句和/或执行的 rowcount 的情况,返回的值将为-1
,该值直接从 DBAPI 传递,并且是 PEP 249 的一部分。但是,所有 DBAPI 都应支持单参数集 UPDATE 和 DELETE 语句的 rowcount。
注意
有关CursorResult.rowcount
的注释:
此属性返回匹配的行数,这不一定与实际修改的行数相同。例如,如果给定的 SET 值与行中已经存在的 SET 值相同,则 UPDATE 语句在给定行上可能没有净变化。这样的行将被匹配,但不会被修改。在同时具有这两种样式的后端(例如 MySQL)上,rowcount 配置为在所有情况下都返回匹配计数。CursorResult.rowcount
的默认值为 仅与 UPDATE 或 DELETE 语句结合使用时有用, 并且仅使用一组参数。对于其他类型的 语句,SQLAlchemy 不会尝试预先记住该值 除非Connection.execution_options.preserve_rowcount
execution 选项。 请注意,与 PEP 249 相反,许多 DBAPI 不支持非 UPDATE 或 DELETE 语句的 rowcount 值,尤其是在返回未完全预缓冲的行时。不支持特定类型语句的 rowcount 的 DBAPI 应返回值-1
对于此类声明。CursorResult.rowcount
在执行具有多个参数集(即 executemany)的单个语句时可能没有意义。大多数 DBAPI 不会对多个参数集的 “rowcount” 值求和,并且将返回-1
访问时。
SQLAlchemy 的 INSERT 语句的 “Insert Many Values” 行为功能确实支持正确填充CursorResult.rowcount
Connection.execution_options.preserve_rowcount
当 execution 选项设置为 True。
使用 RETURNING 的语句可能不支持 rowcount,而是返回-1
值。
-
方法sqlalchemy.engine.CursorResult.
scalar()Any ¶
继承自Result
的Result.scalar()
方法
获取第一行的第一列,然后关闭结果集。
如果没有要提取的行,则返回None
。
不执行验证来测试是否保留其他行。
调用该方法后,对象完全关闭,例如CursorResult.close()
方法。
结果
Python 标量值,如果没有剩余行,则为 None
。
-
方法sqlalchemy.engine.CursorResult.
scalar_one()Any ¶
继承自Result
的Result.scalar_one()
方法
只返回一个标量结果或引发异常。
这相当于调用Result.scalars(),
然后调用ScalarResult.one()。
-
方法sqlalchemy.engine.CursorResult.
scalar_one_or_none()→AnyNone¶
继承自Result
的Result.scalar_one_or_none()
方法
只返回一个标量结果或None
。
-
方法sqlalchemy.engine.CursorResult.
scalars(index: _KeyIndexType = 0)ScalarResult[Any] ¶
继承自Result
的Result.scalars()
方法
返回一个ScalarResult
过滤对象,该对象将返回单个元素而不是Row
对象。
例如:>>> result = conn.execute(text("select int_id from table")) >>> result.scalars().all() [1, 2, 3]
从ScalarResult
获取结果时 filtering 对象,则由Result
将作为列的值返回。
在 1.4 版本加入.
参数
index¶—— 整数或行键,表示要从每行中获取的列,默认为0
表示第一列。
结果
引用此Result
对象的新ScalarResult
筛选对象。
-
方法sqlalchemy.engine.CursorResult.
splice_horizontally(其他)¶
返回一个新的CursorResult,该 CursorResult
将此 CursorResult 的行与另一个CursorResult
的行“水平拼接”在一起CursorResult 的 Cursor Result
中。
提示
此方法是为了 SQLAlchemy ORM 的好处,而不是用于一般用途。
“horizontally splices” 表示对于第一行和第二行中的每一行 result sets 中,将两行连接在一起的新行为 produced 的,然后成为新行。 传入的CursorResult
必须具有相同的行数。通常预计这两个结果集也来自相同的排序顺序,因为结果行是根据它们在结果中的位置拼接在一起的。
这里预期的用例是让多个 INSERT..针对不同表的 RETURNING 语句(肯定需要排序)可以生成一个结果,该结果看起来像这两个表的 JOIN。
例如:r1 = connection.execute( users.insert().returning( users.c.user_name, users.c.user_id, sort_by_parameter_order=True ), user_values, ) r2 = connection.execute( addresses.insert().returning( addresses.c.address_id, addresses.c.address, addresses.c.user_id, sort_by_parameter_order=True, ), address_values, ) rows = r1.splice_horizontally(r2).all() assert rows == [ ("john", 1, 1, "foo@bar.com", 1), ("jack", 2, 2, "bar@bat.com", 2), ]
2.0 版的新Function。
-
方法sqlalchemy.engine.CursorResult.
splice_vertically(其他)¶
返回一个新的CursorResult,该 CursorResult
将此CursorResult
的行与另一个CursorResult
的行“垂直拼接”,即“扩展”。
提示
此方法是为了 SQLAlchemy ORM 的好处,而不是用于一般用途。
“vertical splices” 表示给定结果的行被附加到该游标结果的行中。传入的CursorResult
必须具有表示 与它们在此CursorResult
中的顺序相同。
2.0 版的新Function。
-
方法sqlalchemy.engine.CursorResult.
supports_sane_multi_rowcount()¶
从方言返回supports_sane_multi_rowcount
。
有关背景信息,请参阅CursorResult.rowcount
。
-
方法sqlalchemy.engine.CursorResult.
supports_sane_rowcount()¶
从方言返回supports_sane_rowcount
。
有关背景信息,请参阅CursorResult.rowcount
。
-
属性sqlalchemy.engine.CursorResult.
t¶ -
将 “typed tuple” 键入筛选器应用于返回的行。Result.t
属性是调用Result.tuples()
方法的同义词。
2.0 版的新Function。
-
方法sqlalchemy.engine.CursorResult.
tuples()TupleResult[_TP] ¶
继承自Result
的Result.tuples()
方法
将 “typed tuple” 键入筛选器应用于返回的行。
此方法在运行时返回相同的Result
对象,但注释为返回一个TupleResult
对象,该对象将向 PEP 484 指示纯类型化的键入工具 返回Tuples
实例而不是 rows。这允许元组解包和__getitem__
Row
访问 对象,对于调用了 本身包括键入信息。
2.0 版的新Function。
结果
键入时的TupleResult
类型。
-
methodsqlalchemy.engine.CursorResult.
unique(strategy:Callable[[Any],Any]None=None)Self ¶
继承自Result
的Result.unique()
方法
将唯一筛选应用于此返回的对象结果
。
当不带参数应用此过滤器时,将对返回的行或对象进行过滤,以便返回每一行都是唯一的。默认情况下,用于确定此唯一性的算法是整个 Tuples 的 Python 哈希标识。在某些情况下,可能会使用专门的每个实体哈希方案,例如在使用 ORM 时,会应用一个针对返回对象的主键标识的方案。
唯一筛选条件在所有其他筛选条件之后应用,这意味着 如果返回的列已使用诸如Result.columns()
或Result.scalars()
方法,则 UNIQUING 仅应用于一个或多个列 返回。无论在Result
对象上调用这些方法的顺序如何,都会发生这种情况。
唯一过滤器还会更改用于Result.fetchmany()
和Result.partitions() 的 Result.partitions()
中。当使用Result.unique()
时,这些方法在应用 uniquing 后将继续产生请求的行数或对象数。但是,这必然会影响底层游标或数据源的缓冲行为,因此可能需要对cursor.fetchmany()
进行多次底层调用,以便积累足够的对象,从而提供请求大小的唯一集合。
-
方法sqlalchemy.engine.CursorResult.
yield_per(num: int)Self ¶
配置行获取策略以一次获取num
行。
这会影响迭代 result 对象,或者使用诸如Result.fetchone()
一次返回一行。来自底层游标或其他数据源的数据将在内存中缓冲到这么多行,然后缓冲的集合将一次产生一行或请求多少行。每次清除缓冲区时,它都会刷新到这么多行,如果剩余的行数更少,则刷新为剩余的行数。Result.yield_per()
方法通常用于 与Connection.execution_options.stream_results
execution 选项,这将允许正在使用的数据库 dialect 进行 使用服务器端游标(如果 DBAPI 支持特定的“服务器 side cursor“ 模式与其默认作模式分开。
提示
考虑使用Connection.execution_options.yield_per
execution 选项,该选项将同时设置Connection.execution_options.stream_results
确保使用服务器端游标,以及自动 调用Result.yield_per()
方法以立即建立固定的行缓冲区大小。
这Connection.execution_options.yield_per
execution 选项可用于 ORM作,其中 面向会话
的用法,如 使用 Yield Per 获取大型结果集。与Connection
配合使用的仅核心版本是 SQLAlchemy 1.4.40 的新版本。
在 1.4 版本加入.
参数
num¶ – 每次重新填充缓冲区时要获取的行数。如果设置为小于 1 的值,则获取下一个缓冲区的所有行。
-
-
类 sqlalchemy.engine 中。FilterResult(筛选结果)¶
返回 Object 以外的对象的Result
的包装器行
对象,例如字典或标量对象。FilterResult
是其他结果 API 的通用基础,包括MappingResult
、ScalarResult
和AsyncResult 的 AsyncResult
进行验证。
类签名
类sqlalchemy.engine.FilterResult
(sqlalchemy.engine.ResultInternal
)-
方法sqlalchemy.engine.FilterResult.
close()None ¶
关闭此FilterResult
。
在 1.4.43 版本加入.
-
Attributesqlalchemy.engine.FilterResult.
closed 属性¶
如果基础Result
报告 closed,则返回True
在 1.4.43 版本加入.
-
方法sqlalchemy.engine.FilterResult.
yield_per(num: int)Self ¶
配置行获取策略以一次获取num
行。FilterResult.yield_per()
方法是Result.yield_per()
方法的传递。有关使用说明,请参阅该方法的文档。
1.4.40 版本中的新功能: - 添加了FilterResult.yield_per()
,以便该方法可用于所有结果集实现
-
-
类 sqlalchemy.engine 中。FrozenResult(冻结结果)¶
表示处于适合缓存的 “frozen” 状态的Result
对象。FrozenResult
对象从Result.freeze()
方法的对象。
每次将FrozenResult
作为可调用对象调用时,都会从一组固定数据生成一个新的可迭代Result
对象:result = connection.execute(query) frozen = result.freeze() unfrozen_result_one = frozen() for row in unfrozen_result_one: print(row) unfrozen_result_two = frozen() rows = unfrozen_result_two.all() # ... etc
在 1.4 版本加入.
另请参阅
Re-Executing Statements - 在 ORM 中实现结果集缓存的示例用法。merge_frozen_result()
- 用于将冻结结果合并回Session
的 ORM 函数。
类签名
类sqlalchemy.engine.FrozenResult
(键入。通用
)
-
类 sqlalchemy.engine 中。IteratorResult(迭代器结果)¶
从 Python 迭代器获取数据的Result
Row
对象或类似的 row-like 数据。
在 1.4 版本加入.
成员-
Attributesqlalchemy.engine.IteratorResult.
closed 属性¶
如果此IteratorResult
已关闭,则返回True
在 1.4.43 版本加入.
-
-
类 sqlalchemy.engine 中。MergedResult(合并结果)¶ -
由Result.merge()
方法返回。
在 1.4 版本加入.
-
类 sqlalchemy.engine 中。结果¶
表示一组数据库结果。
1.4 版本中的新功能:Result
对象提供了一个 完全更新了 SQLAlchemy 的使用模型和调用 Facade Core 和 SQLAlchemy ORM。 在 Core 中,它构成了CursorResult
对象,该对象替换了之前的ResultProxy
接口。当使用 ORM 时,一个名为ChunkedIteratorResult
的更高级别的对象 通常使用。
注意
在 SQLAlchemy 1.4 及更高版本中,此对象用于Session.execute()
返回的 ORM 结果,它可以单独或在类似 Tuples 的行中生成 ORM 映射对象的实例。请注意,Result
对象不会像旧版Query
对象那样自动删除重复的实例或行。要在 Python 中对实例或行进行重复数据删除,请使用Result.unique()
修饰符方法。
另请参阅
成员
all(), close(), closed, columns(), fetchall(), fetchmany(), fetchone(), first(), freeze(), keys(), mappings(), merge(), one(), one_or_none(), partitions()、 标量()、 scalar_one()、 scalar_one_or_none()、标量 ()、 t、元组 () 、 unique()、 yield_per()
类签名
类sqlalchemy.engine.Result
(sqlalchemy.engine._WithKeys
,sqlalchemy.engine.ResultInternal
)-
方法sqlalchemy.engine.Result 中。
all()序列[Row[_TP]] ¶
返回序列中的所有行。
调用后关闭结果集。后续调用将返回空序列。
在 1.4 版本加入.
结果Row
对象的序列。
另请参阅
使用服务器端游标(又名流结果) - 如何在不完全在 python 中加载大型结果集的情况式传输大型结果集。
-
方法sqlalchemy.engine.Result 中。
close()无 ¶ close this
Result
.
此方法的行为是特定于实现的,并且是 默认情况下未实现。 该方法通常应结束 result 对象使用的资源,并导致任何 后续迭代或行提取以引发ResourceClosedError 的 ResourceClosedError
错误。
1.4.27 版中的新功能: -.close()
以前并非对所有Result
类都可用,而仅在为 Core 语句执行返回的CursorResult
上可用。由于大多数其他结果对象(即 ORM 使用的对象)都代理了 CursorResult
在任何情况下,这都允许关闭底层游标结果 从 outer façade 中,对于 ORM 查询使用yield_per
执行选项,它不会立即耗尽并自动关闭数据库游标。
-
属性sqlalchemy.engine.Result 的 Result。
已关闭¶
如果此Result
报告 .closed,则返回True
在 1.4.43 版本加入.
-
方法sqlalchemy.engine.Result 中。
columns(*col_expressions: _KeyIndexType)Self ¶
建立应在每行中返回的列。
此方法可用于限制返回的列以及对它们重新排序。给定的表达式列表通常是一系列整数或字符串键名称。它们也可能是对应于给定语句构造的适当ColumnElement
对象。
在 2.0 版更改: 由于 1.4 中的一个 bug,Result.columns()
方法的行为不正确 其中,调用只有一个索引的方法会导致Result
对象生成标量值,而不是Row
对象。 在版本 2.0 中,此行为 已更正,因此调用 具有单个索引的Result.columns()
将生成一个Result
对象,该对象继续生成Row
对象,其中仅包含单个列。
例如:statement = select(table.c.x, table.c.y, table.c.z) result = connection.execute(statement) for z, y in result.columns("z", "y"): ...
从语句本身使用列对象的示例:for z, y in result.columns( statement.selected_columns.c.z, statement.selected_columns.c.y ): ...
在 1.4 版本加入.
参数
*col_expressions¶ – 表示要返回的列。 元素 可以是整数行索引、字符串列名称或适当的ColumnElement
对象。
结果
thisResult
对象。
-
方法sqlalchemy.engine.Result 中。
fetchall()序列[Row[_TP]] ¶ Result.all()
方法的同义词。
-
方法sqlalchemy.engine.Result 中。
fetchmany(size:intNone=None)序列[Row[_TP]] ¶
获取许多行。
当所有行都用完时,返回一个空序列。
提供此方法是为了向后兼容 SQLAlchemy 1.x.x。
要获取组中的行,请使用Result.partitions()
方法。
结果Row
对象的序列。
另请参阅
-
方法sqlalchemy.engine.Result 中。
fetchone()→Row[_TP]无¶
获取一行。
当所有行都用完时,返回 None。
提供此方法是为了向后兼容 SQLAlchemy 1.x.x。
要仅获取结果的第一行,请使用Result.first()
方法。要遍历所有行,请直接遍历Result
对象。
结果Row
对象(如果未应用过滤器),如果没有剩余行,则为 None
。
-
方法sqlalchemy.engine.Result 中。
first()→Row[_TP]无¶
获取第一行,如果不存在行,则为 None
。
关闭结果集并丢弃剩余行。
注意
默认情况下,此方法返回一行,例如 tuple。 要只返回一个标量值,即第一个 列,请使用Result.scalar()
方法,或者将Result.scalars()
和Result.first() 的 Result.first()
中。
此外,与传统 ORM 的行为相比Query.first()
方法,则对 调用的 SQL 查询来生成此结果
;对于在生成行之前在内存中缓冲结果的 DBAPI 驱动程序,所有行都将发送到 Python 进程,并且除第一行之外的所有行都将被丢弃。
结果一个 Row
对象,如果没有剩余行,则为 None。
-
方法sqlalchemy.engine.Result 中。
freeze()FrozenResult[_TP] ¶
返回一个可调用对象,该对象将生成此调用时的结果
。
返回的可调用对象是FrozenResult 的 Froz。
这用于结果集缓存。当结果未使用时,必须在结果上调用该方法,并且调用该方法将完全使用结果。当FrozenResult
从缓存中检索,则可以调用任意次数,其中 它每次都会针对其存储的行集生成一个新的Result
对象。
另请参阅
Re-Executing Statements - 在 ORM 中实现结果集缓存的示例用法。
-
方法sqlalchemy.engine.Result 中。
keys()RMKeyView ¶
继承自sqlalchemy.engine._WithKeys.keys
sqlalchemy.engine._WithKeys
的方法
返回一个可迭代视图,该视图产生将由每个Row
表示的字符串键。
键可以表示 core 语句返回的列的标签或 orm 执行返回的 orm 类的名称。
还可以使用 Python 测试视图的密钥包含in
运算符,该运算符将测试视图中表示的字符串键以及备用键(如 Column 对象)。
在 1.4 版本发生变更: 返回一个键视图对象,而不是一个普通的列表。
-
方法sqlalchemy.engine.Result 中。
mappings()MappingResult ¶
将 mappings 筛选器应用于返回的行,返回MappingResult 的 MappingResult
中。
应用此过滤器后,fetching rows 将返回RowMapping
对象而不是Row
对象。
在 1.4 版本加入.
结果
引用此Result
对象的新MappingResult
筛选对象。
-
方法sqlalchemy.engine.Result 中。
merge(*其他: Result[Any])MergedResult[_TP] ¶
将此Result
与其他兼容的 Result 对象合并。
返回的对象是MergedResult
的实例,它将由给定结果对象的迭代器组成。
新结果将使用此 result 对象中的元数据。后续结果对象必须针对一组相同的结果/游标元数据,否则行为未定义。
-
方法sqlalchemy.engine.Result 中。
one()行[_TP] ¶
只返回一行或引发异常。
如果结果不返回任何行,则引发NoResultFound
,如果返回多行,则引发MultipleResultsFound
。
注意
默认情况下,此方法返回一行,例如 tuple。 要只返回一个标量值,即第一个 列,请使用Result.scalar_one()
方法或组合Result.scalars()
和Result.one() 的 Result.one()
中。
在 1.4 版本加入.
结果
第一行
。
提升:
-
方法sqlalchemy.engine.Result 中。
one_or_none()→Row[_TP]无¶
最多返回一个结果或引发异常。
如果结果没有行,则返回None
。引发MultipleResultsFound
如果返回多行。
在 1.4 版本加入.
结果
第一行
或None
(无行)如果没有可用行。
提升:
-
方法sqlalchemy.engine.Result 中。
partitions(size:intNone=None)Iterator[Sequence[Row[_TP]]]¶
遍历给定大小的行的子列表。
每个列表的大小都与给定的大小相同,但要生成的最后一个列表除外,该列表可能具有少量行数。不会产生空列表。
当迭代器被完全消耗时,result 对象会自动关闭。
请注意,后端驱动程序通常会缓冲整个结果 除非Connection.execution_options.stream_results
execution 选项表示驱动程序不应预先缓冲结果(如果可能)。并非所有驱动程序都支持此选项,对于不支持此选项的驱动程序,此选项将被静默忽略。
当使用 ORM 时,Result.partitions()
方法 从内存的角度来看,当 结合使用 yield_per执行选项,它指示 DBAPI 驱动程序使用服务器端游标(如果可用),并指示 ORM 加载内部一次只从结果构建一定数量的 ORM 对象,然后再产生它们。
在 1.4 版本加入.
参数
size¶ —— 表示生成的每个列表中存在的最大行数。如果为 None,则使用Result.yield_per()
方法设置的值(如果已调用)或Connection.execution_options.yield_per
execution 选项,这在这方面是等效的。 如果 yield_per未设置,它会使用Result.fetchmany()
默认值,它可能是特定于后端的,并且没有明确定义。
结果
列表的迭代器
-
方法sqlalchemy.engine.Result 中。
scalar()任意 ¶
获取第一行的第一列,然后关闭结果集。
如果没有要提取的行,则返回None
。
不执行验证来测试是否保留其他行。
调用该方法后,对象完全关闭,例如CursorResult.close()
方法。
结果
Python 标量值,如果没有剩余行,则为 None
。
-
方法sqlalchemy.engine.Result 中。
scalar_one()Any ¶
只返回一个标量结果或引发异常。
这相当于调用Result.scalars(),
然后调用ScalarResult.one()。
-
方法sqlalchemy.engine.Result 中。
scalar_one_or_none()→AnyNone(无)¶
只返回一个标量结果或None
。
-
方法sqlalchemy.engine.Result 中。
scalars(index: _KeyIndexType = 0)ScalarResult[任意] ¶
返回一个ScalarResult
过滤对象,该对象将返回单个元素而不是Row
对象。
例如:>>> result = conn.execute(text("select int_id from table")) >>> result.scalars().all() [1, 2, 3]
从ScalarResult
获取结果时 filtering 对象,则由Result
将作为列的值返回。
在 1.4 版本加入.
参数
index¶—— 整数或行键,表示要从每行中获取的列,默认为0
表示第一列。
结果
引用此Result
对象的新ScalarResult
筛选对象。
-
属性sqlalchemy.engine.Result 的 Result。
t¶
将 “typed tuple” 键入筛选器应用于返回的行。Result.t
属性是调用Result.tuples()
方法的同义词。
2.0 版的新Function。
-
方法sqlalchemy.engine.Result 中。
tuples()TupleResult[_TP] ¶
将 “typed tuple” 键入筛选器应用于返回的行。
此方法在运行时返回相同的Result
对象,但注释为返回一个TupleResult
对象,该对象将向 PEP 484 指示纯类型化的键入工具 返回Tuples
实例而不是 rows。这允许元组解包和__getitem__
Row
访问 对象,对于调用了 本身包括键入信息。
2.0 版的新Function。
结果
键入时的TupleResult
类型。
-
方法sqlalchemy.engine.Result 中。
unique(strategy:Callable[[Any],Any]None=None)Self ¶
将唯一筛选应用于此返回的对象结果
。
当不带参数应用此过滤器时,将对返回的行或对象进行过滤,以便返回每一行都是唯一的。默认情况下,用于确定此唯一性的算法是整个 Tuples 的 Python 哈希标识。在某些情况下,可能会使用专门的每个实体哈希方案,例如在使用 ORM 时,会应用一个针对返回对象的主键标识的方案。
唯一筛选条件在所有其他筛选条件之后应用,这意味着 如果返回的列已使用诸如Result.columns()
或Result.scalars()
方法,则 UNIQUING 仅应用于一个或多个列 返回。无论在Result
对象上调用这些方法的顺序如何,都会发生这种情况。
唯一过滤器还会更改用于Result.fetchmany()
和Result.partitions() 的 Result.partitions()
中。当使用Result.unique()
时,这些方法在应用 uniquing 后将继续产生请求的行数或对象数。但是,这必然会影响底层游标或数据源的缓冲行为,因此可能需要对cursor.fetchmany()
进行多次底层调用,以便积累足够的对象,从而提供请求大小的唯一集合。
-
方法sqlalchemy.engine.Result 中。
yield_per(num: int)自身 ¶
配置行获取策略以一次获取num
行。
这会影响迭代 result 对象,或者使用诸如Result.fetchone()
一次返回一行。来自底层游标或其他数据源的数据将在内存中缓冲到这么多行,然后缓冲的集合将一次产生一行或请求多少行。每次清除缓冲区时,它都会刷新到这么多行,如果剩余的行数更少,则刷新为剩余的行数。Result.yield_per()
方法通常用于 与Connection.execution_options.stream_results
execution 选项,这将允许正在使用的数据库 dialect 进行 使用服务器端游标(如果 DBAPI 支持特定的“服务器 side cursor“ 模式与其默认作模式分开。
提示
考虑使用Connection.execution_options.yield_per
execution 选项,该选项将同时设置Connection.execution_options.stream_results
确保使用服务器端游标,以及自动 调用Result.yield_per()
方法以立即建立固定的行缓冲区大小。
这Connection.execution_options.yield_per
execution 选项可用于 ORM作,其中 面向会话
的用法,如 使用 Yield Per 获取大型结果集。与Connection
配合使用的仅核心版本是 SQLAlchemy 1.4.40 的新版本。
在 1.4 版本加入.
参数
num¶ – 每次重新填充缓冲区时要获取的行数。如果设置为小于 1 的值,则获取下一个缓冲区的所有行。
-
-
类 sqlalchemy.engine 中。标量结果¶ -
ScalarResult
对象是通过调用Result.scalars()
方法。ScalarResult
的一个特殊限制是它没有fetchone()
方法;由于fetchone()
的语义是None
值表示不再有结果,因此这与ScalarResult
不兼容,因为无法区分作为行值的 None 和作为指示符的None
。用
next(result)
来单独接收值。
成员
all(), close(), closed, fetchall(), fetchmany(), first(), one(), one_or_none(), partitions(), unique(), yield_per()-
methodsqlalchemy.engine.ScalarResult.
all()序列[_R] ¶
返回序列中的所有标量值。
等效于Result.all(),
但返回的是标量值,而不是Row
对象。
-
方法sqlalchemy.engine.ScalarResult.
close()None ¶
继承自FilterResult
的FilterResult.close()
方法
关闭此FilterResult
。
在 1.4.43 版本加入.
-
Attributesqlalchemy.engine.ScalarResult.
closed 属性¶
继承自FilterResult
的FilterResult.closed
属性
如果基础Result
报告 closed,则返回True
在 1.4.43 版本加入.
-
方法sqlalchemy.engine.ScalarResult.
fetchall()序列[_R] ¶ ScalarResult.all()
方法的同义词。
-
methodsqlalchemy.engine.ScalarResult.
fetchmany(size:intNone=None)Sequence[_R] ¶
获取多个对象。
等效于Result.fetchmany(),
但返回的是标量值,而不是Row
对象。
-
methodsqlalchemy.engine.ScalarResult.
first()→_RNone¶
获取第一个对象,如果不存在对象,则为None
。
等效于Result.first(),
但返回的是标量值,而不是Row
对象。
-
方法sqlalchemy.engine.ScalarResult.
1()_R ¶
只返回一个对象或引发异常。
等效于Result.one(),
但返回的是标量值,而不是Row
对象。
-
方法sqlalchemy.engine.ScalarResult.
one_or_none()→_RNone¶
最多返回一个对象或引发异常。
等效于Result.one_or_none(),
但返回标量值而不是Row
对象。
-
方法sqlalchemy.engine.ScalarResult.
partitions(size:intNone=None)Iterator[Sequence[_R]]¶
遍历给定大小的元素的子列表。
等效于Result.partitions(),
但返回的是标量值,而不是Row
对象。
-
methodsqlalchemy.engine.ScalarResult.
unique(strategy:Callable[[Any],Any]None=None)Self ¶
将唯一筛选应用于此返回的对象ScalarResult 的 ScalarResult
中。
有关使用详情,请参阅Result.unique()。
-
方法sqlalchemy.engine.ScalarResult.
yield_per(num: int)Self ¶
继承自FilterResult
的FilterResult.yield_per()
方法
配置行获取策略以一次获取num
行。FilterResult.yield_per()
方法是Result.yield_per()
方法的传递。有关使用说明,请参阅该方法的文档。
1.4.40 版本中的新功能: - 添加了FilterResult.yield_per()
,以便该方法可用于所有结果集实现
-
-
类 sqlalchemy.engine 中。MappingResult(映射结果)¶ -
MappingResult
对象是通过调用Result.mappings()
方法。
成员
all(), close(), closed, columns(), fetchall(), fetchmany(), fetchone(), first(), keys(), one(), one_or_none(), partitions(), unique(), yield_per()
类签名
类sqlalchemy.engine.MappingResult
(sqlalchemy.engine._WithKeys
,sqlalchemy.engine.FilterResult
)-
methodsqlalchemy.engine.MappingResult.
all()序列[RowMapping] ¶
返回序列中的所有标量值。
等效于Result.all(),
不同之处在于RowMapping
值,而不是Row
对象。
-
方法sqlalchemy.engine.MappingResult.
close()None ¶
继承自FilterResult
的FilterResult.close()
方法
关闭此FilterResult
。
在 1.4.43 版本加入.
-
Attributesqlalchemy.engine.MappingResult.
closed 属性¶
继承自FilterResult
的FilterResult.closed
属性
如果基础Result
报告 closed,则返回True
在 1.4.43 版本加入.
-
methodsqlalchemy.engine.MappingResult.
columns(*col_expressions: _KeyIndexType)Self ¶
建立应在每行中返回的列。
-
方法sqlalchemy.engine.MappingResult.
fetchall()序列[RowMapping] ¶ MappingResult.all()
方法的同义词。
-
方法sqlalchemy.engine.MappingResult.
fetchmany(size:intNone=None)Sequence[RowMapping] ¶
获取多个对象。
等效于Result.fetchmany(),
不同之处在于RowMapping
值,而不是Row
对象。
-
methodsqlalchemy.engine.MappingResult.
fetchone()→RowMappingNone¶
获取一个对象。
等同于Result.fetchone(),
不同之处在于RowMapping
值,而不是Row
对象。
-
methodsqlalchemy.engine.MappingResult.
first()→RowMappingNone¶
获取第一个对象,如果不存在对象,则为None
。
等效于Result.first(),
不同之处在于RowMapping
值,而不是Row
对象。
-
方法sqlalchemy.engine.MappingResult.
keys()RMKeyView ¶
继承自sqlalchemy.engine._WithKeys.keys
sqlalchemy.engine._WithKeys
的方法
返回一个可迭代视图,该视图产生将由每个Row
表示的字符串键。
键可以表示 core 语句返回的列的标签或 orm 执行返回的 orm 类的名称。
还可以使用 Python 测试视图的密钥包含in
运算符,该运算符将测试视图中表示的字符串键以及备用键(如 Column 对象)。
在 1.4 版本发生变更: 返回一个键视图对象,而不是一个普通的列表。
-
方法sqlalchemy.engine.MappingResult.
one()RowMapping ¶
只返回一个对象或引发异常。
等效于Result.one(),
不同之处在于RowMapping
值,而不是Row
对象。
-
方法sqlalchemy.engine.MappingResult.
one_or_none()→RowMappingNone¶
最多返回一个对象或引发异常。
等效于Result.one_or_none(),
但RowMapping
值,而不是Row
对象。
-
方法sqlalchemy.engine.MappingResult.
partitions(size:intNone=None)Iterator[Sequence[RowMapping]] ¶
遍历给定大小的元素的子列表。
等同于Result.partitions(),
不同之处在于RowMapping
值,而不是Row
对象。
-
methodsqlalchemy.engine.MappingResult.
unique(strategy:Callable[[Any],Any]None=None)Self ¶
将唯一筛选应用于此返回的对象MappingResult 的 MappingResult
中。
有关使用详情,请参阅Result.unique()。
-
方法sqlalchemy.engine.MappingResult.
yield_per(num: int)Self ¶
继承自FilterResult
的FilterResult.yield_per()
方法
配置行获取策略以一次获取num
行。FilterResult.yield_per()
方法是Result.yield_per()
方法的传递。有关使用说明,请参阅该方法的文档。
1.4.40 版本中的新功能: - 添加了FilterResult.yield_per()
,以便该方法可用于所有结果集实现
-
-
类 sqlalchemy.engine 中。行¶
表示单个结果行。Row
对象表示数据库结果的一行。 是的 通常在 SQLAlchemy 的 1.x 系列中与CursorResult
对象,但是从 SQLAlchemy 1.4 开始,ORM 也将其用于类似元组的结果。Row
对象寻求尽可能像 Python 命名元组。有关行上的映射(即字典)行为,例如测试键的包含,请参阅Row._mapping
属性。
另请参阅
使用 SELECT 语句 - 包括从 SELECT 语句中选择行的示例。
在 1.4 版本发生变更: 已将RowProxy
重命名为Row
。Row
不再是“代理”对象,因为它包含最终形式的数据,现在主要充当命名元组。类似映射的功能被移动到Row._mapping
属性。看 RowProxy 不再是“代理”;现在称为 Row,其行为类似于此更改的背景增强的命名元组。
类签名
类sqlalchemy.engine.Row
(sqlalchemy.engine._py_row.BaseRow
,collections.abc.Sequence
,typing.通用
)-
方法sqlalchemy.engine.Row 中。
_asdict()Dict[str, Any] ¶
返回一个新 dict,该 dict 将字段名称映射到其相应的值。
此方法类似于名为 tuple._asdict()
的 Python 方法,并通过将dict()
构造函数应用于Row._mapping
属性。
在 1.4 版本加入.
另请参阅
-
属性sqlalchemy.engine.Row 中。
_fields¶
返回一个字符串键的元组,由此表示行
。
键可以表示 core 语句返回的列的标签或 orm 执行返回的 orm 类的名称。
此属性类似于 Python 命名的 tuple._fields
属性。
在 1.4 版本加入.
另请参阅
-
属性sqlalchemy.engine.Row 中。
_mapping¶
返回此Row
的RowMapping
。
此对象为行中包含的数据提供一致的 Python 映射(即字典)接口。行
本身的行为类似于命名元组。
另请参阅
在 1.4 版本加入.
-
属性sqlalchemy.engine.Row 中。
_t¶ Row._tuple()
的同义词。
另请参阅
-
方法sqlalchemy.engine.Row 中。
_tuple()_TP ¶
返回此Row
的 'tuple' 形式。
在运行时,此方法返回 “self”;Row
对象为 已经是一个命名元组。但是,在类型级别,如果Row
类型化,则“元组”返回类型将是 PEP 484元组
数据类型,其中包含有关单个元素的类型信息,支持类型化解包和属性访问。
2.0.19 版本的新Function: -Row._tuple()
方法取代了以前的Row.tuple()
方法,该方法现在带有下划线以避免与列名发生名称冲突,就像Row
上的其他命名元组方法一样。
-
属性sqlalchemy.engine.Row 中。
t¶ Row._tuple()
的同义词。
2.0 版的新Function。
-
方法sqlalchemy.engine.Row 中。
tuple()_TP ¶
返回此Row
的 'tuple' 形式。
自 2.0.19 版本起已移除:Row.tuple()
方法已被弃用,取而代之的是Row._tuple();
所有Row
方法和库级属性都应加下划线以避免名称冲突。请使用Row._tuple()。
2.0 版的新Function。
-
-
类 sqlalchemy.engine 中。RowMapping¶
将列名和对象映射到Row
的Mapping
值。RowMapping
可通过Row
中的Row._mapping
属性,以及从MappingResult
对象提供的可迭代接口中,由Result.mappings()
方法。RowMapping
提供对行内容的 Python 映射(即字典)访问。这包括支持测试特定键(字符串列名或对象)的包含,以及键、值和项的迭代:for row in result: if "a" in row._mapping: print("Column 'a': %s" % row._mapping["a"]) print("Column b: %s" % row._mapping[table.c.b])
1.4 版本中的新功能:RowMapping
对象替换了以前由数据库结果行提供的类似 mapping 的访问,该行现在寻求主要像命名 Tuples 一样运行。
类签名
类sqlalchemy.engine.RowMapping
(sqlalchemy.engine._py_row.BaseRow
,collections.abc.Mapping
,typing.通用
)-
方法sqlalchemy.engine.RowMapping 中。
items()ROMappingItemsView ¶
返回底层Row
中元素的键/值元组视图。
-
方法sqlalchemy.engine.RowMapping 中。
keys()RMKeyView ¶
返回底层Row
表示的字符串列名称的 'keys' 视图。
-
方法sqlalchemy.engine.RowMapping 中。
values()ROMappingKeysValuesView ¶
返回基础Row
中表示的值的视图。
-
-
类 sqlalchemy.engine 中。元组结果¶
类型化为返回纯 Python 元组而不是行的Result
。
由于Row
在各个方面都已经像一个 Tuples,所以这个类是一个纯类型类,所以在运行时仍然使用常规的 Result
。
类签名
类sqlalchemy.engine.TupleResult
(sqlalchemy.engine.FilterResult
,sqlalchemy.util.langhelpers.TypingOnly
)