术语表

1.x 风格
2.0 风格
1.x 风格
2.0 风格

这些术语在 SQLAlchemy 1.4 中是新增的,指的是 SQLAlchemy 1.4 -> 2.0 的过渡计划,详见 SQLAlchemy 2.0 - 主要迁移指南。“1.x 风格” 指的是在 SQLAlchemy 1.x 系列及更早版本(例如 1.3、1.2 等)中记录的 API 使用方式,“2.0 风格” 指的是 API 在 2.0 版本中的外观。版本 1.4 几乎实现了 2.0 的所有 API,以所谓的“过渡模式”实现,而版本 2.0 仍然保留了旧的 Query 对象,以允许旧代码在很大程度上保持与 2.0 的兼容性。

ACID
ACID 模型

“原子性 (Atomicity)、一致性 (Consistency)、隔离性 (Isolation)、持久性 (Durability)” 的首字母缩写;一组属性,保证数据库事务被可靠地处理。(通过维基百科)

关联关系

一种双层 关系,使用中间的关联表将两个表链接在一起。关联关系与 多对多 关系的不同之处在于,多对多表由完整的类映射,而不是像多对多那样由 sqlalchemy.orm.relationship() 构造隐式处理,因此额外的属性是显式可用的。

例如,如果我们想将员工与项目关联起来,同时存储该员工在项目中的特定角色,则关系模式可能如下所示

CREATE TABLE employee (
    id INTEGER PRIMARY KEY,
    name VARCHAR(30)
)

CREATE TABLE project (
    id INTEGER PRIMARY KEY,
    name VARCHAR(30)
)

CREATE TABLE employee_project (
    employee_id INTEGER PRIMARY KEY,
    project_id INTEGER PRIMARY KEY,
    role_name VARCHAR(30),
    FOREIGN KEY employee_id REFERENCES employee(id),
    FOREIGN KEY project_id REFERENCES project(id)
)

上面 SQLAlchemy 声明式映射可能如下所示

class Employee(Base):
    __tablename__ = "employee"

    id = Column(Integer, primary_key=True)
    name = Column(String(30))


class Project(Base):
    __tablename__ = "project"

    id = Column(Integer, primary_key=True)
    name = Column(String(30))


class EmployeeProject(Base):
    __tablename__ = "employee_project"

    employee_id = Column(Integer, ForeignKey("employee.id"), primary_key=True)
    project_id = Column(Integer, ForeignKey("project.id"), primary_key=True)
    role_name = Column(String(30))

    project = relationship("Project", backref="project_employees")
    employee = relationship("Employee", backref="employee_projects")

可以为项目添加具有角色的员工

proj = Project(name="Client A")

emp1 = Employee(name="emp1")
emp2 = Employee(name="emp2")

proj.project_employees.extend(
    [
        EmployeeProject(employee=emp1, role_name="tech lead"),
        EmployeeProject(employee=emp2, role_name="account executive"),
    ]
)

另请参阅

多对多

原子性

原子性是 ACID 模型的组成部分之一,它要求每个事务都是“要么全部要么全无”:如果事务的一部分失败,则整个事务失败,数据库状态保持不变。原子系统必须保证在每种情况下,包括电源故障、错误和崩溃,都具有原子性。(通过维基百科)

已附加

指示当前与特定 Session 关联的 ORM 对象。

backref
双向关系

关系 系统的扩展,其中两个不同的 relationship() 对象可以相互关联,以便它们在内存中协调,因为任何一方发生更改。构建这两个关系最常见的方式是显式地对一方使用 relationship() 函数,并为其指定 backref 关键字,以便自动创建另一个 relationship()。我们可以针对我们在 一对多 中使用的示例来说明这一点,如下所示

class Department(Base):
    __tablename__ = "department"
    id = Column(Integer, primary_key=True)
    name = Column(String(30))
    employees = relationship("Employee", backref="department")


class Employee(Base):
    __tablename__ = "employee"
    id = Column(Integer, primary_key=True)
    name = Column(String(30))
    dep_id = Column(Integer, ForeignKey("department.id"))

Backref 可以应用于任何关系,包括一对多、多对一和 多对多

绑定参数
绑定参数
绑定参数
绑定参数

绑定参数是将数据传递到 DBAPI 数据库驱动程序的主要方式。虽然要调用的操作基于 SQL 语句字符串,但数据值本身是单独传递的,其中驱动程序包含逻辑,可以安全地处理这些字符串并将它们传递到后端数据库服务器,这可能涉及将参数格式化到 SQL 字符串本身中,或者使用单独的协议将它们传递到数据库。

数据库驱动程序执行此操作的具体系统对调用者来说并不重要;重点是,在外部,数据应始终单独传递,而不是作为 SQL 字符串本身的一部分。这对于充分防范 SQL 注入以及允许驱动程序获得最佳性能都至关重要。

另请参阅

预处理语句 - 在维基百科上

绑定参数 - 在 Use The Index, Luke! 上

发送参数 - 在 SQLAlchemy 统一教程

候选键

关系代数 术语,指的是形成行唯一标识键的属性或属性集。一行可以有多个候选键,每个候选键都适合用作该行的主键。表的主键始终是候选键。

笛卡尔积

给定两个集合 A 和 B,笛卡尔积是所有有序对 (a, b) 的集合,其中 a 在 A 中,b 在 B 中。

在 SQL 数据库方面,当我们从两个或多个表(或其他子查询)中选择,而没有在表行之间建立任何类型的标准(直接或间接)时,就会发生笛卡尔积。如果我们同时从表 A 和表 B 中进行 SELECT,我们会得到表 A 的每一行与表 B 的第一行匹配,然后表 A 的每一行与表 B 的第二行匹配,依此类推,直到表 A 的每一行都与表 B 的每一行配对。

笛卡尔积会导致生成巨大的结果集,如果未阻止,很容易使客户端应用程序崩溃。

级联

SQLAlchemy 中使用的术语,用于描述在特定对象上发生的 ORM 持久性操作如何扩展到与该对象直接关联的其他对象。在 SQLAlchemy 中,这些对象关联是使用 relationship() 构造配置的。relationship() 包含一个名为 relationship.cascade 的参数,该参数提供有关某些持久性操作如何级联的选项。

“级联”一词以及 SQLAlchemy 中此系统的总体架构,无论好坏,都是从 Hibernate ORM 借用来的。

另请参阅

级联

检查约束

检查约束是在关系数据库的表中添加或更新条目时定义有效数据的条件。检查约束应用于表中的每一行。

(通过维基百科)

可以使用如下 DDL 在标准 SQL 中将检查约束添加到表中

ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5);
列子句

SELECT 语句的一部分,它枚举要在结果集中返回的 SQL 表达式。表达式直接跟随 SELECT 关键字,并且是以逗号分隔的各个表达式列表。

例如:

SELECT user_account.name, user_account.email
FROM user_account WHERE user_account.name = 'fred'

上面,列 user_acount.nameuser_account.email 的列表是 SELECT 的列子句。

复合主键

具有多个列的 主键。特定的数据库行是基于两列或多列而不是单个值唯一的。

另请参阅

主键

一致性

一致性是 ACID 模型的组成部分之一,它确保任何事务都会将数据库从一个有效状态转移到另一个有效状态。写入数据库的任何数据都必须根据所有定义的规则有效,包括但不限于 约束、级联、触发器以及它们的任何组合。(通过维基百科)

约束
约束
受约束的

在关系数据库中建立的规则,用于确保数据的有效性和一致性。常见的约束形式包括 主键约束外键约束检查约束

关联
关联子查询
关联子查询

如果 子查询 依赖于封闭 SELECT 中的数据,则该子查询是关联的。

下面,子查询从 email_address 表中选择聚合值 MIN(a.id),以便它将为 user_account.id 的每个值调用,将此列的值与 email_address.user_account_id 列关联起来

SELECT user_account.name, email_address.email
 FROM user_account
 JOIN email_address ON user_account.id=email_address.user_account_id
 WHERE email_address.id = (
    SELECT MIN(a.id) FROM email_address AS a
    WHERE a.user_account_id=user_account.id
 )

上面的子查询引用了 user_account 表,该表本身不在此嵌套查询的 FROM 子句中。相反,user_account 表是从封闭查询接收的,其中从 user_account 中选择的每一行都会导致子查询的单独执行。

关联子查询在大多数情况下都存在于紧邻的封闭 SELECT 语句的 WHERE 子句列子句 中,以及 ORDER BY 或 HAVING 子句中。

在不太常见的情况下,关联子查询可能存在于封闭 SELECTFROM 子句 中;在这些情况下,关联通常是由于封闭 SELECT 本身包含在另一个 SELECT 的 WHERE、ORDER BY、列或 HAVING 子句中,例如

SELECT parent.id FROM parent
WHERE EXISTS (
    SELECT * FROM (
        SELECT child.id AS id, child.parent_id AS parent_id, child.pos AS pos
        FROM child
        WHERE child.parent_id = parent.id ORDER BY child.pos
    LIMIT 3)
WHERE id = 7)

从一个 SELECT 直接到另一个通过其 FROM 子句封闭关联查询的 SELECT 的关联是不可能的,因为只有在封闭语句的 FROM 子句中的原始源行可用后,关联才能进行。

crud
CRUD

意思是“创建 (Create)、读取 (Read)、更新 (Update)、删除 (Delete)”的首字母缩写。SQL 中的术语指的是创建、修改和删除数据库中数据的一组操作,也称为 DML,通常指的是 INSERTUPDATEDELETE 语句。

游标

一种控制结构,可以遍历数据库中的记录。在 Python DBAPI 中,游标对象实际上是语句执行的起点,也是用于获取结果的接口。

循环复杂度

一种基于程序源代码中可能路径数量的代码复杂性度量。

另请参阅

循环复杂度

DBAPI
pep-249

DBAPI 是短语 “Python 数据库 API 规范” 的缩写。这是 Python 中广泛使用的规范,用于定义所有数据库连接包的通用使用模式。DBAPI 是一个“低级别” API,通常是 Python 应用程序中用于与数据库通信的最低级别系统。SQLAlchemy 的 方言 系统围绕 DBAPI 的操作构建,提供单个方言类,这些类在特定数据库引擎之上的特定 DBAPI 上提供服务;例如,create_engine() URL postgresql+psycopg2://@localhost/test 指的是 psycopg2 DBAPI/方言组合,而 URL mysql+mysqldb://@localhost/test 指的是 MySQL for Python DBAPI/方言组合。

DDL

数据定义语言 (Data Definition Language) 的首字母缩写。DDL 是关系数据库用于配置表、约束和数据库模式中的其他永久对象的 SQL 子集。SQLAlchemy 提供了丰富的 API,用于构建和发出 DDL 表达式。

已删除

这描述了对象在 Session 中可能具有的主要对象状态之一;已删除的对象是以前持久化的对象,并且在刷新中发出了 DELETE 语句到数据库以删除其行。一旦会话事务提交,对象将移动到 detached 状态;或者,如果会话事务回滚,则 DELETE 将被撤消,对象将移回 persistent 状态。

描述符
描述符

在 Python 中,描述符是具有“绑定行为”的对象属性,其属性访问已被 描述符协议 中的方法覆盖。这些方法是 __get__()__set__()__delete__()。如果为对象定义了这些方法中的任何一个,则称其为描述符。

在 SQLAlchemy 中,描述符被大量使用,以便在映射类上提供属性行为。当一个类被映射为如下所示时

class MyClass(Base):
    __tablename__ = "foo"

    id = Column(Integer, primary_key=True)
    data = Column(String)

MyClass 类的定义完成时,它将被 映射,此时 iddata 属性,最初是 Column 对象,将被 instrumentation 系统替换为 InstrumentedAttribute 的实例,这些实例是描述符,提供上述 __get__()__set__()__delete__() 方法。InstrumentedAttribute 将在类级别使用时生成 SQL 表达式

>>> print(MyClass.data == 5)
data = :data_1

在实例级别,跟踪值的更改,并且还 延迟加载 从数据库卸载的属性

>>> m1 = MyClass()
>>> m1.id = 5
>>> m1.data = "some data"

>>> from sqlalchemy import inspect
>>> inspect(m1).attrs.data.history.added
"some data"
已分离

这描述了对象在 Session 中可能具有的主要对象状态之一;已分离的对象是具有数据库标识(即主键)但未与任何会话关联的对象。先前 persistent 并且由于被逐出或拥有会话已关闭而从其会话中删除的对象,将移动到已分离状态。当对象在会话之间移动或在会话与外部对象缓存之间移动时,通常使用已分离状态。

方言

在 SQLAlchemy 中,“方言”是一个 Python 对象,表示允许在特定类型的数据库后端和该数据库的特定类型的 Python 驱动程序(或 DBAPI)上进行数据库操作的信息和方法。SQLAlchemy 方言是 Dialect 类的子类。

另请参阅

引擎配置

鉴别器

结果集列,在 多态 加载期间使用,以确定应将哪种映射类应用于特定的传入结果行。

DML

数据操作语言 (Data Manipulation Language) 的首字母缩写。DML 是关系数据库用于修改表中数据的 SQL 子集。DML 通常指的是 INSERT、UPDATE 和 DELETE 这三个广泛熟悉的语句,也称为 CRUD(“创建 (Create)、读取 (Read)、更新 (Update)、删除 (Delete)” 的首字母缩写)。

领域模型

在问题解决和软件工程中,领域模型是与特定问题相关的所有主题的概念模型。它描述了各种实体、它们的属性、角色和关系,以及控制问题领域的约束。

(通过维基百科)

DQL

数据查询语言 (Data Query Language) 的首字母缩写。DQL 是关系数据库用于读取表中数据的 SQL 子集。DQL 几乎完全指 SQL SELECT 构造作为正在使用的顶级 SQL 语句。

持久性

持久性是 ACID 模型的一个属性,这意味着一旦事务被提交,它将保持提交状态,即使发生断电、崩溃或错误。例如,在关系数据库中,一旦一组 SQL 语句执行,结果需要永久存储(即使数据库在此之后立即崩溃)。(通过维基百科)

预加载
预加载
已预加载
预加载
预加载

在对象关系映射中,“预加载”指的是一个属性,该属性的值在从数据库加载对象本身的同时填充其数据库端的值。在 SQLAlchemy 中,“预加载” 术语通常指的是使用 relationship() 构造在映射之间链接的相关集合和对象实例,但也可能指加载额外的列属性,通常来自与正在查询的特定表相关的其他表,例如当使用 继承 映射时。

预加载与 延迟加载 相反。

另请参阅

关系加载技术

executemany

此术语指的是 PEP 249 DBAPI 规范的一部分,指示可以针对具有多个参数集的数据库连接调用的单个 SQL 语句。具体方法称为 cursor.executemany(),与用于单语句调用的 cursor.execute() 方法相比,它在行为上有许多差异。“executemany” 方法多次执行给定的 SQL 语句,每个参数集执行一次。使用 executemany 的一般原理是提高性能,其中 DBAPI 可以使用诸如预先准备语句一次,或者以其他方式优化多次调用同一语句的技术。

当使用 Connection.execute() 方法且传递了参数字典列表时,SQLAlchemy 通常会自动使用 cursor.executemany() 方法;这向 SQLAlchemy Core 指示 SQL 语句和已处理的参数集应传递给 cursor.executemany(),其中驱动程序将为每个参数字典单独调用该语句。

与所有已知的 DBAPI 一起使用的 cursor.executemany() 方法的一个主要限制是,当使用此方法时,cursor 未配置为返回行。对于大多数后端(一个值得注意的例外是 python-oracledb / cx_Oracle DBAPI),这意味着诸如 INSERT..RETURNING 之类的语句通常不能直接与 cursor.executemany() 一起使用,因为 DBAPI 通常不会将每次 INSERT 执行的单行聚合在一起。

为了克服此限制,从 2.0 系列开始,SQLAlchemy 实现了另一种形式的 “executemany”,称为 INSERT 语句的“多值插入”行为。此功能使用 cursor.execute() 调用 INSERT 语句,该语句将在一个往返中继续处理多个参数集,从而产生与使用 cursor.executemany() 相同的效果,同时仍支持 RETURNING。

另请参阅

发送多个参数 - “executemany” 教程介绍

INSERT 语句的“多值插入”行为 - SQLAlchemy 功能,允许将 RETURNING 与 “executemany” 一起使用

过期
已过期
过期
过期中
过期

在 SQLAlchemy ORM 中,指的是当 持久化 或有时 分离 对象中的数据被擦除时,这样,当下次访问对象的属性时,将发出 延迟加载 SQL 查询,以便刷新此对象在当前正在进行的事务中存储的数据。

另请参阅

刷新 / 过期

外观模式

充当前端接口的对象,用于掩盖更复杂的底层或结构代码。

刷新
刷新
已刷新

指的是 工作单元 用于将更改发出到数据库的实际过程。在 SQLAlchemy 中,此过程通过 Session 对象发生,通常是自动的,但也可以手动控制。

另请参阅

刷新

外键约束

两个表之间的引用约束。外键是关系表中的一个字段或一组字段,它与另一个表的 候选键 匹配。外键可用于交叉引用表。(通过维基百科)

外键约束可以使用标准 SQL 中的 DDL 添加到表中,如下所示

ALTER TABLE employee ADD CONSTRAINT dep_id_fk
FOREIGN KEY (employee) REFERENCES department (dep_id)
FROM 子句

SELECT 语句的一部分,指示行的初始来源。

一个简单的 SELECT 语句将在其 FROM 子句中包含一个或多个表名。 多个来源用逗号分隔

SELECT user.name, address.email_address
FROM user, address
WHERE user.id=address.user_id

FROM 子句也是指定显式连接的地方。 我们可以使用单个 FROM 元素重写上面的 SELECT,该元素由两个表的 JOIN 组成

SELECT user.name, address.email_address
FROM user JOIN address ON user.id=address.user_id
标识键

与 ORM 映射对象关联的键,用于标识它们在数据库中的主键标识,以及它们在 Session 标识映射 中的唯一标识。

在 SQLAlchemy 中,您可以使用 inspect() API 查看 ORM 对象的标识键,以返回 InstanceState 跟踪对象,然后查看 InstanceState.key 属性

>>> from sqlalchemy import inspect
>>> inspect(some_object).key
(<class '__main__.MyTable'>, (1,), None)

另请参阅

标识映射

标识映射

Python 对象及其数据库标识之间的映射。 标识映射是与 ORM Session 对象关联的集合,并维护每个数据库对象的单个实例,并以其标识为键。 这种模式的优点是,对于特定数据库标识发生的所有操作都透明地协调到单个对象实例上。 当结合 隔离的 事务使用标识映射时,从实际的角度来看,引用已知具有特定主键的对象可以被认为是实际数据库行的代理。

另请参阅

标识映射 (通过 Martin Fowler)

通过主键获取 - 如何通过主键在标识映射中查找对象

命令式
声明式

在 SQLAlchemy ORM 中,这些术语指的是将 Python 类映射到数据库表的两种不同风格。

insertmanyvalues

这指的是 SQLAlchemy 特有的功能,它允许 INSERT 语句在单个语句中发出数千个新行,同时允许服务器生成的值使用 RETURNING 或类似机制从语句内联返回,以实现性能优化。 该功能旨在对选定的后端透明可用,但确实提供了一些配置选项。 有关此功能的完整描述,请参阅 INSERT 语句的 “Insert Many Values” 行为 部分。

instrumentation
instrumented
instrumenting

Instrumentation 指的是增强特定类的功能和属性集的过程。 理想情况下,该类的行为应与常规类保持接近,只是提供了额外的行为和功能。 SQLAlchemy 映射 过程,除其他外,向映射类添加了数据库启用的 描述符,每个描述符代表一个特定的数据库列或与相关类的关系。

隔离
隔离的
隔离级别

ACID 模型的隔离属性确保事务的并发执行产生一个系统状态,该状态与事务串行执行(即一个接一个)获得的状态相同。 每个事务都必须在完全隔离的情况下执行,即如果 T1 和 T2 并发执行,则每个事务都应保持彼此独立。 (通过维基百科)

延迟初始化

一种延迟某些初始化操作的策略,例如创建对象、填充数据或建立与其他服务的连接,直到需要这些资源时才执行。

延迟加载
延迟加载s
延迟加载的
延迟加载ing

在对象关系映射中,“延迟加载”指的是某个属性在一段时间内不包含其数据库端的值,通常是在对象首次加载时。 相反,该属性接收一个记忆化,使其在首次使用时访问数据库并加载其数据。 使用这种模式,对象获取中的复杂性和花费的时间有时可以减少,因为相关表的属性不需要立即处理。

延迟加载与 预先加载 相反。

在 SQLAlchemy 中,延迟加载是 ORM 的一项关键功能,适用于在用户定义的类上 映射的 属性。 当访问引用数据库列或相关对象的属性,但不存在已加载的值时,ORM 会使用当前对象在 持久 状态下关联的 Session,并在当前事务中发出 SELECT 语句,如果事务尚未进行,则启动新事务。 如果对象处于 分离 状态且未与任何 Session 关联,则认为这是一个错误状态,并引发 信息性异常

另请参阅

延迟加载 (通过 Martin Fowler)

N+1 问题

列加载选项 - 包括有关 ORM 映射列延迟加载的信息

关系加载技术 - 包括有关 ORM 相关对象延迟加载的信息

使用 AsyncSession 时避免隐式 IO - 关于在使用 异步 I/O (asyncio) 扩展时避免延迟加载的提示

多对多

sqlalchemy.orm.relationship() 的一种风格,它通过中间表将两个表链接在一起。 使用此配置,左侧的任意数量的行可以引用右侧的任意数量的行,反之亦然。

员工可以与项目关联的模式

CREATE TABLE employee (
    id INTEGER PRIMARY KEY,
    name VARCHAR(30)
)

CREATE TABLE project (
    id INTEGER PRIMARY KEY,
    name VARCHAR(30)
)

CREATE TABLE employee_project (
    employee_id INTEGER PRIMARY KEY,
    project_id INTEGER PRIMARY KEY,
    FOREIGN KEY employee_id REFERENCES employee(id),
    FOREIGN KEY project_id REFERENCES project(id)
)

上面,employee_project 表是多对多表,它自然形成一个复合主键,由每个相关表的主键组成。

在 SQLAlchemy 中,sqlalchemy.orm.relationship() 函数可以以几乎透明的方式表示这种关系风格,其中多对多表使用纯表元数据指定

class Employee(Base):
    __tablename__ = "employee"

    id = Column(Integer, primary_key=True)
    name = Column(String(30))

    projects = relationship(
        "Project",
        secondary=Table(
            "employee_project",
            Base.metadata,
            Column("employee_id", Integer, ForeignKey("employee.id"), primary_key=True),
            Column("project_id", Integer, ForeignKey("project.id"), primary_key=True),
        ),
        backref="employees",
    )


class Project(Base):
    __tablename__ = "project"

    id = Column(Integer, primary_key=True)
    name = Column(String(30))

上面,定义了 Employee.projects 和反向引用的 Project.employees 集合

proj = Project(name="Client A")

emp1 = Employee(name="emp1")
emp2 = Employee(name="emp2")

proj.employees.extend([emp1, emp2])
多对一

relationship() 的一种风格,它将父映射器表中的外键链接到相关表的主键。 然后,每个父对象可以引用零个或一个相关的对象。

反过来,相关的对象将与引用它们的任意数量的父对象具有隐式或显式的 一对多 关系。

一个多对一模式的示例 (请注意,它与 一对多 模式相同)

CREATE TABLE department (
    id INTEGER PRIMARY KEY,
    name VARCHAR(30)
)

CREATE TABLE employee (
    id INTEGER PRIMARY KEY,
    name VARCHAR(30),
    dep_id INTEGER REFERENCES department(id)
)

employeedepartment 的关系是多对一,因为许多员工记录可以与单个部门关联。 SQLAlchemy 映射可能如下所示

class Department(Base):
    __tablename__ = "department"
    id = Column(Integer, primary_key=True)
    name = Column(String(30))


class Employee(Base):
    __tablename__ = "employee"
    id = Column(Integer, primary_key=True)
    name = Column(String(30))
    dep_id = Column(Integer, ForeignKey("department.id"))
    department = relationship("Department")
映射
映射的
映射类
ORM 映射类

当一个类与 Mapper 类的实例关联时,我们说该类是 “映射的”。 此过程将该类与数据库表或其他 selectable 构造关联,以便可以使用 Session 持久化和加载它的实例。

另请参阅

ORM 映射类概述

marshalling (编组)
数据编组

将对象的内存表示转换为适合存储或传输到系统另一部分的数据格式的过程,当数据必须在计算机程序的各个部分之间或从一个程序移动到另一个程序时。 就 SQLAlchemy 而言,我们经常需要将数据 “编组” 为适合传递到关系数据库的格式。

另请参阅

编组 (通过维基百科)

增强现有类型 - SQLAlchemy 的 TypeDecorator 通常用于数据编组,因为数据在发送到数据库以进行 INSERT 和 UPDATE 语句时,以及在使用 SELECT 语句检索数据时进行 “解组”。

metadata (元数据)
数据库元数据
表元数据

术语 “元数据” 通常指的是 “描述数据的数据”;自身表示某些其他类型的数据的格式和/或结构的数据。 在 SQLAlchemy 中,术语 “元数据” 通常指的是 MetaData 构造,它是关于表、列、约束和其他可能存在于特定数据库中的 DDL 对象的集合信息。

方法链
generative (生成式)

“方法链”,在 SQLAlchemy 文档中称为 “生成式”,是一种面向对象的技巧,对象的状态通过调用对象上的方法来构建。 对象具有任意数量的方法,每个方法都返回一个新对象 (或在某些情况下是同一个对象),其中添加了额外的状态到对象。

最常使用方法链的两个 SQLAlchemy 对象是 Select 对象和 Query 对象。 例如,一个 Select 对象可以通过调用 Select.where()Select.order_by() 方法,为其 WHERE 子句以及 ORDER BY 子句分配两个表达式

stmt = (
    select(user.c.name)
    .where(user.c.id > 5)
    .where(user.c.name.like("e%"))
    .order_by(user.c.name)
)

上面的每个方法调用都返回原始 Select 对象的副本,并添加了额外的限定符。

mixin 类 (混入类)
mixin 类s (混入类)

一种常见的面向对象模式,其中一个类包含供其他类使用的方法或属性,而无需成为这些其他类的父类。

N+1 问题
N+1

N+1 问题是 延迟加载 模式的常见副作用,应用程序希望迭代结果集中每个成员的相关属性或集合,其中该属性或集合设置为通过延迟加载模式加载。 最终结果是发出一个 SELECT 语句来加载父对象的初始结果集; 然后,当应用程序迭代每个成员时,会为每个成员发出一个额外的 SELECT 语句,以便为该成员加载相关属性或集合。 最终结果是,对于 N 个父对象的结果集,将发出 N+1 个 SELECT 语句。

N+1 问题可以通过使用 预先加载 来缓解。

一对多

relationship() 的一种风格,它将父映射器表的主键链接到相关表的外键。 然后,每个唯一的父对象可以引用零个或多个唯一的关联对象。

反过来,相关的对象将与其父对象具有隐式或显式的 多对一 关系。

一对多模式的示例 (请注意,它与 多对一 模式相同)

CREATE TABLE department (
    id INTEGER PRIMARY KEY,
    name VARCHAR(30)
)

CREATE TABLE employee (
    id INTEGER PRIMARY KEY,
    name VARCHAR(30),
    dep_id INTEGER REFERENCES department(id)
)

departmentemployee 的关系是一对多,因为许多员工记录可以与单个部门关联。 SQLAlchemy 映射可能如下所示

class Department(Base):
    __tablename__ = "department"
    id = Column(Integer, primary_key=True)
    name = Column(String(30))
    employees = relationship("Employee")


class Employee(Base):
    __tablename__ = "employee"
    id = Column(Integer, primary_key=True)
    name = Column(String(30))
    dep_id = Column(Integer, ForeignKey("department.id"))
ORM-annotated (ORM 注解的)
annotations (注解)

短语 “ORM-annotated” 指的是 SQLAlchemy 的内部方面,其中 Core 对象(例如 Column 对象)可以携带额外的运行时信息,这些信息将其标记为属于特定的 ORM 映射。 该术语不应与常用短语 “type annotation (类型注解)” 混淆,后者指的是 Python 源代码 “类型提示”,用于 PEP 484 中引入的静态类型。

SQLAlchemy 的大多数文档化代码示例都格式化有一个关于 “Annotated Example (注解示例)” 或 “Non-annotated Example (非注解示例)” 的小注释。 这指的是示例是否是 PEP 484 注解的,与 SQLAlchemy 的 “ORM-annotated (ORM 注解的)” 概念无关。

当短语 “ORM-annotated (ORM 注解的)” 出现在文档中时,它指的是 Core SQL 表达式对象,例如 TableColumnSelect 对象,它们源自一个或多个 ORM 映射,或者引用源自一个或多个 ORM 映射的子元素,因此当传递给 ORM 方法(例如 Session.execute())时,将具有 ORM 特定的解释和/或行为。 例如,当我们从 ORM 映射构造 Select 对象时,例如 ORM 教程 中所示的 User

>>> stmt = select(User)

上面 Select 的内部状态引用了 User 映射到的 TableUser 类本身不会立即被引用。 这就是 Select 构造如何保持与 Core 级别进程兼容的原因 (请注意,Select._raw_columns 成员是私有的,不应由最终用户代码访问)

>>> stmt._raw_columns
[Table('user_account', MetaData(), Column('id', Integer(), ...)]

但是,当我们的 Select 传递给 ORM Session 时,与对象间接关联的 ORM 实体用于在 ORM 上下文中解释此 Select。 实际的 “ORM 注解” 可以在另一个私有变量 ._annotations 中看到

>>> stmt._raw_columns[0]._annotations
immutabledict({
  'entity_namespace': <Mapper at 0x7f4dd8098c10; User>,
  'parententity': <Mapper at 0x7f4dd8098c10; User>,
  'parentmapper': <Mapper at 0x7f4dd8098c10; User>
})

因此,我们将 stmt 称为 ORM-annotated select() (ORM 注解的 select() 对象)。 这是一个 Select 语句,其中包含额外的信息,这些信息将使其在传递给诸如 Session.execute() 之类的方法时以 ORM 特定的方式解释。

pending (待定)

这描述了对象在 Session 中可以具有的主要对象状态之一; 待定对象是一个没有数据库标识的新对象,但最近已与会话关联。 当会话发出刷新并且行被插入时,对象移动到 持久 状态。

persistent (持久)

这描述了对象在 Session 中可以具有的主要对象状态之一; 持久对象是具有数据库标识 (即主键) 并且当前与会话关联的对象。 任何先前 待定 且现在已插入的对象都处于持久状态,从数据库中由会话加载的任何对象也是如此。 当持久对象从会话中移除时,它被称为 分离的

plugin (插件)
plugin-enabled (插件启用)
plugin-specific (插件特定)

“plugin-enabled (插件启用)” 或 “plugin-specific (插件特定)” 通常指示 SQLAlchemy Core 中的函数或方法,这些函数或方法在 ORM 上下文中使用时行为会有所不同。

SQLAlchemy 允许 Core 构造(例如 Select 对象)参与 “plugin (插件)” 系统,该系统可以将额外的行为和功能注入到默认情况下不存在的对象中。

具体来说,主要的 “plugin (插件)” 是 “orm (对象关系映射)” 插件,它是 SQLAlchemy ORM 使用 Core 构造来组成和执行返回 ORM 结果的 SQL 查询的系统的基础。

polymorphic (多态)
polymorphically (多态地)

指的是一次处理多种类型的功能。 在 SQLAlchemy 中,该术语通常应用于 ORM 映射类的概念,由此查询操作将根据结果集中的信息返回不同的子类,通常通过检查结果中称为 鉴别器 的特定列的值来实现。

SQLAlchemy 中的多态加载意味着使用三种不同方案中的一种或组合来映射类层次结构; “joined (连接)”、“single (单一)” 和 “concrete (具体)”。 映射类继承层次结构 部分完整地描述了继承映射。

primary key (主键)
主键约束

一种 约束,它唯一地定义表中每一行的特征。 主键必须由任何其他行都无法复制的特征组成。 主键可以由单个属性或多个属性组合而成。 (通过维基百科)

表的主键通常(尽管并非总是)在 CREATE TABLE DDL 中定义

CREATE TABLE employee (
     emp_id INTEGER,
     emp_name VARCHAR(30),
     dep_id INTEGER,
     PRIMARY KEY (emp_id)
)
读已提交

四种数据库 隔离 级别之一,读已提交的特点是事务不会暴露于来自其他并发事务的任何尚未提交的数据,从而防止所谓的 “脏读”。 但是,在读已提交的情况下,可能存在不可重复读,这意味着如果另一个事务已提交更改,则在第二次读取时,行中的数据可能会发生更改。

读未提交

数据库 隔离性 级别之一,“读取未提交内容”的特点是,在事务内对数据库数据所做的更改,在该事务提交之前不会成为永久性的。然而,在“读取未提交内容”级别下,可能会在一个事务的范围内看到其他事务中未提交的数据;这些被称为“脏读”。

反射
已反射

在 SQLAlchemy 中,此术语指的是查询数据库的模式目录,以便加载有关现有表、列、约束和其他构造的信息的功能。SQLAlchemy 包括可以为此信息提供原始数据的功能,以及可以自动从数据库模式目录构建 Core/ORM 可用的 Table 对象的功能。

另请参阅

反射数据库对象 - 关于数据库反射的完整背景信息。

使用反射表进行声明式映射 - 关于将 ORM 映射与反射表集成的背景信息。

注册表

一个对象,通常是全局可访问的,其中包含关于程序状态的长期存在的信息,这些信息通常对程序的许多部分都很有用。

关系型
关系代数

Edgar F. Codd 开发的一种代数系统,用于建模和查询存储在关系数据库中的数据。

关系
关系们

两个映射类之间的连接单元,对应于数据库中两个表之间的某种关系。

关系使用 SQLAlchemy 函数 relationship() 定义。一旦创建,SQLAlchemy 会检查参数和涉及的底层映射,以便将关系分类为三种类型之一:一对多多对一多对多。通过这种分类,关系构造处理在数据库中持久化适当链接的任务,以响应内存中的对象关联,以及基于数据库中当前的链接将对象引用和集合加载到内存中的任务。

另请参阅

关系配置

发布
发布们
已发布

在 SQLAlchemy 的上下文中,“发布”一词指的是结束特定数据库连接使用的过程。SQLAlchemy 具有连接池的使用特性,这允许配置数据库连接的生命周期。当使用池化连接时,“关闭”它的过程,即调用类似 connection.close() 的语句,可能会导致连接返回到现有池,或者可能导致实际关闭该连接所引用的底层 TCP/IP 连接 - 发生哪种情况取决于配置以及池的当前状态。因此,我们使用术语发布来表示“当我们完成使用连接后,无论你对连接做什么”。

该术语有时会在短语“发布事务资源”中使用,更明确地表明我们实际“发布”的是在连接上累积的任何事务状态。在大多数情况下,从表中选择、发出更新等操作会在该连接上获取 隔离 状态以及潜在的行或表锁。此状态都本地于连接上的特定事务,并在我们发出回滚时发布。连接池的一个重要特性是,当我们将连接返回到池时,也会调用 DBAPI 的 connection.rollback() 方法,以便在连接设置为再次使用时,它处于“干净”状态,并且不保留对先前一系列操作的引用。

另请参阅

连接池

可重复读

数据库 隔离性 级别之一,“可重复读”具有 读取已提交内容 的所有隔离性,此外还具有在事务中读取的任何特定行从那时起保证在事务持续时间内不会有任何后续外部值更改(即来自其他并发 UPDATE 语句)的特性。

RETURNING

这是一个非 SQL 标准子句,由某些后端以各种形式提供,它提供在执行 INSERT、UPDATE 或 DELETE 语句时返回结果集的服务。可以返回匹配行的任何列集,就像它们是从 SELECT 语句产生的一样。

RETURNING 子句为常见的更新/选择场景提供了显着的性能提升,包括检索内联或默认生成的在创建时的主键值和默认值,以及以原子方式获取服务器生成的默认值的方法。

PostgreSQL 中 RETURNING 的一个惯用示例看起来像

INSERT INTO user_account (name) VALUES ('new name') RETURNING id, timestamp

上面,INSERT 语句在执行时将提供一个结果集,其中包括列 user_account.iduser_account.timestamp 的值,上面应该已生成为默认值,因为它们没有以其他方式包含(但请注意,任何系列的列或 SQL 表达式都可以放入 RETURNING 中,而不仅仅是默认值列)。

目前支持 RETURNING 或类似构造的后端有 PostgreSQL、SQL Server、Oracle Database 和 Firebird。PostgreSQL 和 Firebird 的实现通常功能齐全,而 SQL Server 和 Oracle Database 的实现则存在一些注意事项。在 SQL Server 上,对于 INSERT 和 UPDATE 语句,该子句被称为“OUTPUT INSERTED”,对于 DELETE 语句,则被称为“OUTPUT DELETED”;主要的注意事项是不支持与此关键字结合使用的触发器。在 Oracle Database 中,它被称为“RETURNING…INTO”,并且要求将值放入 OUT 参数中,这意味着不仅语法笨拙,而且一次只能用于一行。

SQLAlchemy 的 UpdateBase.returning() 系统在这些后端的 RETURNING 系统之上提供了一个抽象层,以提供用于返回列的一致接口。ORM 还包括许多在可用时利用 RETURNING 的优化。

可选择的

SQLAlchemy 中使用的术语,用于描述表示行集合的 SQL 构造。它在很大程度上类似于 关系代数 中“关系”的概念。在 SQLAlchemy 中,当使用 SQLAlchemy Core 时,子类化 Selectable 类的对象被认为是可用作“可选择的”。最常见的两种构造是 TableSelect 语句。

哨兵
插入哨兵

这是一个 SQLAlchemy 特有的术语,指的是一个 Column,它可以用于批量 insertmanyvalues 操作,以针对使用 RETURNING 或类似方法返回的行跟踪 INSERTed 数据记录。当 insertmanyvalues 功能对许多行一次执行优化的 INSERT..RETURNING 语句,同时仍然能够保证返回行的顺序与输入数据匹配时,这种列配置是必要的。

对于典型的用例,SQLAlchemy SQL 编译器可以自动使用代理整数主键列作为“插入哨兵”,并且不需要用户配置。对于其他各种服务器生成的主键值不太常见的情况,可以在 表元数据 中可选地配置显式“插入哨兵”列,以便优化一次插入多行的 INSERT 语句。

可串行化

数据库 隔离性 级别之一,“可串行化”具有 可重复读 的所有隔离性,此外,在基于锁的方法中,保证不会发生所谓的“幻读”;这意味着在本事务范围内 INSERT 或 DELETEd 的行在本事务中将不可检测。在本事务中读取的行保证继续存在,而不存在的行保证不会从另一个事务中出现或插入。

可串行化隔离通常依赖于锁定行或行范围以实现此效果,并且可能会增加死锁的机会并降低性能。但是,也存在非基于锁的方案,但这些方案必须依赖于在检测到写入冲突时拒绝事务。

Session

ORM 数据库操作的容器或范围。Session 从数据库加载实例,跟踪对映射实例的更改,并在刷新时在单个工作单元中持久化更改。

另请参阅

使用 Session

子查询
标量子查询

指的是嵌入在封闭 SELECT 语句中的 SELECT 语句。

子查询有两种一般形式,一种称为“标量选择”,它必须精确返回一行和一列,另一种形式充当“派生表”,并充当另一个选择的 FROM 子句的行源。标量选择有资格放在封闭选择的 WHERE 子句列子句、ORDER BY 子句或 HAVING 子句中,而派生表形式有资格放在封闭 SELECT 的 FROM 子句中。

示例

  1. 放置在封闭 SELECT列子句 中的标量子查询。此示例中的子查询是 相关子查询,因为其选择的行部分是通过封闭语句给出的。

    SELECT id, (SELECT name FROM address WHERE address.user_id=user.id)
    FROM user
  2. 放置在封闭 SELECTWHERE 子句 中的标量子查询。此示例中的子查询不相关,因为它选择固定结果。

    SELECT id, name FROM user
    WHERE status=(SELECT status_id FROM status_code WHERE code='C')
  3. 放置在封闭 SELECTFROM 子句 中的派生表子查询。这样的子查询几乎总是被赋予别名。

    SELECT user.id, user.name, ad_subq.email_address
    FROM
        user JOIN
        (select user_id, email_address FROM address WHERE address_type='Q') AS ad_subq
        ON user.id = ad_subq.user_id
瞬态

这描述了对象在 Session 中可以拥有的主要对象状态之一;瞬态对象是一个新对象,它没有任何数据库标识,并且尚未与会话关联。当对象添加到会话时,它将移动到 待定 状态。

唯一约束
唯一键索引

唯一键索引可以唯一标识数据库表中的每一行数据值。唯一键索引包含单个数据库表中的单个列或一组列。如果未使用 NULL 值,则数据库表中的任何两个不同的行或数据记录都不能在这些唯一键索引列中具有相同的数据值(或数据值组合)。根据其设计,一个数据库表可以有多个唯一键索引,但最多只有一个主键索引。

(通过维基百科)

工作单元

一种软件架构,其中持久化系统(例如对象关系映射器)维护对一系列对象所做更改的列表,并定期将所有这些待处理的更改刷新到数据库。

SQLAlchemy 的 Session 实现了工作单元模式,其中使用诸如 Session.add() 之类的方法添加到 Session 的对象将参与工作单元样式的持久化。

要逐步了解 SQLAlchemy 中工作单元持久化的外观,请从 使用 ORM 进行数据操作 部分开始,该部分位于 SQLAlchemy 统一教程 中。然后,有关更多详细信息,请参阅常规参考文档中的 使用 Session 的基础知识

版本 ID 列

在 SQLAlchemy 中,这指的是使用特定的表列来跟踪特定行的“版本”,因为行会更改值。虽然有不同类型的关系模式以不同的方式使用“版本 ID 列”,但 SQLAlchemy 的 ORM 包括一个特定功能,允许将此类列配置为在用新信息 UPDATEd 行时测试陈旧数据的一种手段。如果我们尝试将新数据放入行中时,此列的最后已知“版本”与该行的版本不匹配,我们就知道我们正在处理陈旧信息。

还有其他存储数据库中“版本化”行的方法,通常称为“时间”数据。除了 SQLAlchemy 的版本控制功能外,文档中还提供了一些其他示例,请参阅下面的链接。

另请参阅

配置版本计数器 - SQLAlchemy 的内置版本 ID 功能。

版本控制对象 - 时间上版本控制行的其他映射示例。

WHERE 子句

SELECT 语句的一部分,指示应通过其过滤行的条件。它是跟在关键字 WHERE 后面的单个 SQL 表达式。

SELECT user_account.name, user_account.email
FROM user_account
WHERE user_account.name = 'fred' AND user_account.status = 'E'

上面,短语 WHERE user_account.name = 'fred' AND user_account.status = 'E' 构成了 SELECT 的 WHERE 子句。