词汇表

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 模型

“原子性、一致性、隔离性、持久性”的首字母缩写;一套保证数据库事务可靠处理的属性。(来自维基百科)

关联关系

一种两层级的 关系,它使用中间的关联表将两个表链接在一起。关联关系不同于 多对多 关系,因为多对多表由完整类映射,而不是像多对多关系那样被 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 模型的组成部分之一,它要求每个事务都是“要么全部完成,要么全部不完成”:如果事务的一部分失败,整个事务都会失败,并且数据库状态将保持不变。原子系统必须保证在任何情况下都具有原子性,包括电源故障、错误和崩溃。(来自维基百科)

已附加

表示当前与特定 会话 关联的 ORM 对象。

反向引用
双向关系

关系 系统的扩展,通过它,两个不同的 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"))

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

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

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

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

另请参阅

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

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

发送参数 - 在 SQLAlchemy 统一教程

候选键

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

笛卡尔积

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

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

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

级联

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

术语“级联”以及 SQLAlchemy 中此系统的整体架构借鉴了 Hibernate ORM,无论好坏。

另请参阅

级联

检查约束

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

(来自维基百科)

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

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.emailSELECT 的列子句。

复合主键

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

另请参阅

主键

一致性

一致性是 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

一个首字母缩略词,代表“创建、更新、删除”。在 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

数据定义语言的缩写。DDL 是关系数据库用来配置表、约束和其他数据库模式中持久对象的 SQL 子集。SQLAlchemy 提供了一个丰富的 API 用于构建和发出 DDL 表达式。

已删除的

这描述了对象在会话中可以具有的主要对象状态之一;已删除的对象是以前是持久性的对象,并在刷新过程中对数据库发出过 DELETE 语句以删除其行。对象将在会话的事务提交后移动到分离状态;或者,如果会话的事务回滚,DELETE 将被还原,对象将返回到持久状态。

描述符
描述符

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

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

class MyClass(Base):
    __tablename__ = "foo"

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

MyClass类将在其定义完成后被映射,此时iddata属性(最初为Column对象)将被仪器系统替换为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"
分离的

这描述了对象在会话中可以具有的主要对象状态之一;分离的对象是具有数据库标识(即主键)但与任何会话都不关联的对象。以前是持久的对象,要么是因为它被清除,要么是因为拥有它的会话关闭,而从其会话中移除,将进入分离状态。分离状态通常用于在会话之间移动对象或在外部对象缓存中移动对象时。

方言

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

另请参阅

引擎配置

鉴别器

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

DML

数据操作语言的缩写。DML 是关系数据库用来修改表中数据的 SQL 子集。DML 通常指的是 INSERT、UPDATE 和 DELETE 这三个广为人知的语句,也称为CRUD(“创建、读取、更新、删除”的缩写)。

领域模型

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

(来自维基百科)

DQL

数据查询语言的缩写。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未配置为返回行。对于大多数后端(cx_Oracle、/ OracleDB DBAPI 是一个明显的例外),这意味着诸如INSERT..RETURNING之类的语句通常无法直接与cursor.executemany()一起使用,因为 DBAPI 通常不会将每次 INSERT 执行的单行聚合在一起。

为了克服这个限制,从 2.0 版本开始,SQLAlchemy 实现了一种名为“Insert Many Values” 行为(用于 INSERT 语句)的“executemany”的替代形式。此功能使用cursor.execute()调用一个 INSERT 语句,该语句将在一轮行程中处理多个参数集,从而产生与使用cursor.executemany()相同的效果,同时仍然支持 RETURNING。

另请参阅

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

“Insert Many Values” 行为(用于 INSERT 语句) - 允许 RETURNING 与“executemany”一起使用的 SQLAlchemy 功能

失效
失效
失效
失效
失效

在 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对象关联的集合,并维护每个数据库对象的单个实例,这些实例根据其标识进行键控。这种模式的优点是,对特定数据库标识执行的所有操作都透明地协调到单个对象实例上。当在与隔离事务结合使用标识映射时,从实际的角度来看,对已知具有特定主键的对象的引用可以被认为是对实际数据库行的代理。

另请参阅

标识映射(来自马丁·福勒)

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

命令式
声明式

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

insertmanyvalues

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

instrumentation
instrumented
instrumenting

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

isolation
isolated
isolation level

ACID 模型的隔离属性确保事务的并发执行会导致系统状态,该状态与事务按顺序执行(即一个接一个)获得的状态相同。每个事务必须完全隔离地执行,即如果 T1 和 T2 并发执行,那么每个事务都应独立于另一个。(通过维基百科)

lazy initialization

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

lazy load
lazy loads
lazy loaded
lazy loading

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

延迟加载与 急切加载 相反。

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

另请参阅

Lazy Load (via Martin Fowler)

N plus one problem

Column Loading Options - 包括有关 ORM 映射列的延迟加载的信息

Relationship Loading Techniques - 包括有关 ORM 相关对象的延迟加载的信息

Preventing Implicit IO when Using AsyncSession - 使用 Asynchronous I/O (asyncio) 扩展时,避免延迟加载的提示

many to many

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])
many to one

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")

另请参阅

关系

一对多

backref

mapping
mapped
mapped class
ORM mapped class

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

marshalling
data marshalling

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

另请参阅

Marshalling (via Wikipedia)

Augmenting Existing Types - SQLAlchemy 的 TypeDecorator 通常用于将数据编组到数据库中以进行 INSERT 和 UPDATE 语句,以及在使用 SELECT 语句检索数据时“反编组”数据。

metadata
database metadata
table metadata

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

方法链
生成式

“方法链”,在 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 类

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

N 加一问题
N 加一

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

使用 急切加载 可以缓解 N 加一问题。

一对多

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"))

另请参阅

关系

多对一

backref

ORM 注解
注释

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

大多数 SQLAlchemy 的文档代码示例都使用关于“带注释示例”或“非带注释示例”的小注释进行格式化。这指的是该示例是否 PEP 484 注解,与 SQLAlchemy 的“ORM 注解”概念无关。

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

>>> 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 注解 select()** 对象。它是一个 Select 语句,包含额外的信息,这些信息会导致它在传递给像 Session.execute() 这样的方法时以 ORM 特定的方式进行解释。

待处理

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

持久

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

插件
启用插件
特定于插件

“启用插件”或“特定于插件”通常表示 SQLAlchemy Core 中的一个函数或方法,它在 ORM 上下文中使用时会有不同的行为。

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

具体来说,主要的“插件”是“orm”插件,它是 SQLAlchemy ORM 使用 Core 结构来组合和执行返回 ORM 结果的 SQL 查询的系统的基础。

多态
多态地

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

SQLAlchemy 中的多态加载意味着使用一个或三个不同的方案组合来映射一个类层次结构;“连接”、“单个”和“具体”。映射类继承层次结构 部分全面描述了继承映射。

主键
主键约束

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

表的 DDL 中通常,但不总是定义主键。

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

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

读未提交

数据库 隔离级别 之一,读未提交功能是事务中对数据库数据所做的更改在事务提交之前不会变得永久。但是,在读未提交中,其他事务中未提交的数据可能在另一个事务的范围内可见;这些被称为“脏读”。

反射
反射

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

另请参阅

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

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

注册表

一个对象,通常是全局可访问的,它包含有关某些程序状态的持久信息,这些信息通常对程序的许多部分都很有用。

关系型
关系代数

由埃德加·F·科德开发的代数系统,用于对关系数据库中存储的数据进行建模和查询。

关系
关系

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

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

另请参阅

关系配置

释放
释放
释放

在 SQLAlchemy 上下文中,术语“释放”指的是结束对特定数据库连接的使用。SQLAlchemy 具有使用连接池的功能,这允许对数据库连接的寿命进行配置。当使用池化连接时,关闭它的过程,即调用类似 connection.close() 的语句,可能会将连接返回到现有池,或者它可能会实际上关闭该连接引用的底层 TCP/IP 连接 - 哪个过程取决于配置以及池的当前状态。因此,我们使用术语 *释放* 来代替,表示“在我们完成使用连接后,用它们做任何你做的事情”。

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

另请参阅

连接池

可重复读

数据库 隔离级别 之一,可重复读功能包含 读已提交 的所有隔离功能,以及在事务中读取的任何特定行从该点起保证在该事务持续时间内不会出现任何后续外部值更改(即来自其他并发 UPDATE 语句)。

RETURNING

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

RETURNING 子句既为常见的更新/选择场景提供了巨大的性能提升,包括在创建它们的那一刻检索内联或默认生成的 主键值和默认值,又提供了一种以原子方式获取服务器生成的默认值的方法。

RETURNING 的一个示例,是 PostgreSQL 的惯用用法,如下所示

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

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

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

SQLAlchemy 的 UpdateBase.returning() 系统在这些后端 RETURNING 系统之上提供了一层抽象,以便为返回列提供一致的接口。ORM 还包含许多利用 RETURNING(如果可用)进行优化的功能。

可选择项

SQLAlchemy 中使用的一个术语,用于描述表示行集合的 SQL 结构。它与 关系代数 中的“关系”概念非常相似。在 SQLAlchemy 中,子类化 Selectable 类的对象在使用 SQLAlchemy Core 时被认为可用作“可选择项”。最常见的两个结构是 TableSelect 语句。

哨兵
插入哨兵

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

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

可序列化

数据库的四个隔离级别之一,可序列化包含了可重复读的所有隔离性,并在基于锁的方法中额外保证不会发生“幻读”;这意味着在其他事务范围内插入或删除的行在本事务中不可见。在本事务中读取的行保证继续存在,不存在的行保证不会从其他事务中插入或出现。

可序列化隔离通常依靠对行或行范围进行锁定来实现这种效果,这可能会增加死锁的可能性并降低性能。也存在一些非锁定方案,但它们必然依赖于在检测到写入冲突时拒绝事务。

会话

ORM 数据库操作的容器或范围。会话从数据库加载实例,跟踪对映射实例的更改,并在冲洗时将更改持久化到一个工作单元中。

另请参阅

使用会话

子查询
标量子查询

指的是一个嵌套在封闭的 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. 一个放置在封闭 SELECT 语句的 WHERE 子句 中的标量子查询。此示例中的子查询不相关,因为它选择固定结果。

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

    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
瞬态

它描述了对象在 会话 中可能具有的主要对象状态之一;瞬态对象是一个新对象,它没有数据库标识,并且尚未与会话关联。当对象被添加到会话时,它将变为 待处理 状态。

唯一约束
唯一键索引

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

(来自维基百科)

工作单元

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

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

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

版本 ID 列

在 SQLAlchemy 中,它指的是使用特定表列来跟踪特定行的“版本”,因为行会更改值。虽然存在不同类型的关系模式以不同方式使用“版本 ID 列”,但 SQLAlchemy 的 ORM 包含一个特定功能,允许将此类列配置为一种测试方法,用于在用新信息更新行时测试数据是否陈旧。如果此列的最后已知“版本”与我们尝试将新数据放入行时的行版本不匹配,则说明我们正在操作陈旧信息。

还存在其他方法来存储数据库中的“版本化”行,通常被称为“时间”数据。除了 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 子句。