元数据 / 架构¶
当我说 table.drop()
/ metadata.drop_all() 时
,我的程序挂起了¶
这通常对应于两个条件:1. 使用 PostgreSQL,它对表锁非常严格,以及 2. 您有一个连接仍处于打开状态,该连接包含表上的锁,并且与用于 DROP 语句的连接不同。这是该模式的最小版本:
connection = engine.connect()
result = connection.execute(mytable.select())
mytable.drop(engine)
在上图中,连接池连接仍处于签出状态;此外,上面的 Result 对象还维护了指向此连接的链接。如果使用“隐式执行”,则结果将保持此连接打开,直到结果对象关闭或所有行都用尽。
对 mytable.drop(engine)
的调用尝试在从 Engine
获取的第二个连接上发出 DROP TABLE,该连接将锁定。
解决方案是在发出 DROP TABLE 之前关闭所有连接:
connection = engine.connect()
result = connection.execute(mytable.select())
# fully read result sets
result.fetchall()
# close connections
connection.close()
# now locks are removed
mytable.drop(engine)
SQLAlchemy 是否支持 ALTER TABLE、CREATE VIEW、CREATE TRIGGER、Schema Upgrade 功能?¶
SQLAlchemy 中不直接存在常规 ALTER 支持。对于临时的特殊 DDL,可以使用 DDL
和相关构造。有关此主题的讨论,请参阅 Customizing DDL 。
更全面的选项是使用架构迁移工具,例如 Alembic 或 SQLAlchemy-Migrate;有关此内容的讨论,请参阅 通过迁移更改数据库对象 。
如何按依赖关系的顺序对 Table 对象进行排序?¶
这可以通过 MetaData.sorted_tables
函数获得:
metadata_obj = MetaData()
# ... add Table objects to metadata
ti = metadata_obj.sorted_tables
for t in ti:
print(t)
如何将 CREATE TABLE/ DROP TABLE 输出作为字符串获取?¶
现代 SQLAlchemy 具有表示 DDL作的子句构造。这些可以像任何其他 SQL 表达式一样呈现为字符串:
from sqlalchemy.schema import CreateTable
print(CreateTable(mytable))
要获取特定于特定引擎的字符串,请执行以下作:
print(CreateTable(mytable).compile(engine))
还有一种特殊形式的 Engine
可通过
create_mock_engine()
允许使用以下配方将整个元数据创建序列转储为字符串:
from sqlalchemy import create_mock_engine
def dump(sql, *multiparams, **params):
print(sql.compile(dialect=engine.dialect))
engine = create_mock_engine("postgresql+psycopg2://", dump)
metadata_obj.create_all(engine, checkfirst=False)
Alembic 工具还支持“离线”SQL 生成模式,该模式将数据库迁移呈现为 SQL 脚本。
如何子类化 Table/Column 以提供某些行为/配置?¶
Table
和 Column
不是直接子类化的良好目标。但是,有一些简单的方法可以使用创建函数获取构造中行为,以及与架构对象之间的链接相关的行为,例如使用附件事件的约束约定或命名约定。其中许多技术的示例可以在 命名约定 中看到。