SQLAlchemy 2.0 新特性
Key Points
-
SQLAlchemy 2.0 相较于 1.4 版本有许多重大改动,包括核心功能、ORM 使用和新增特性。
-
核心变化包括移除自动提交功能,需明确管理事务;查询和 DML 语句的语法调整。
-
ORM 改动涉及查询方式更新,关系策略优化,以及移除部分旧功能。
-
新增功能包括更好的类型支持、批量插入性能提升和数据库反射优化。
-
迁移可能需要逐步完成,建议参考官方文档以确保兼容性。
Core Changes
SQLAlchemy 2.0 的核心部分有显著调整:
-
不再支持库级别的自动提交,事务需通过 with engine.begin() 或 conn.commit() 明确管理。
-
移除“无连接”执行,所有操作必须通过连接执行。
-
Connection.execute() 变得更严格,不接受直接字符串(需用 text()),只支持命名参数,且不支持 *args 或 **kwargs。
ORM Changes
ORM 方面的变化包括:
-
Session.query() 被标记为遗留功能,建议使用 Session.execute(select()) 结合 Result.scalars() 获取 ORM 对象。
-
Session.get() 替代 Query.get() 用于按主键访问对象。
-
连接和加载选项现在使用属性名而非字符串,移除链式连接功能。
-
lazy="dynamic" 被 lazy="write_only" 替代,提供更好的性能和异步支持。
New Features
SQLAlchemy 2.0 引入了多项新功能:
-
增强的类型支持,方便使用 Python 类型提示。
-
批量插入操作性能优化,尤其在 RETURNING 子句下。
-
支持 ORM 启用 DML 语句并使用 RETURNING,提升效率。
-
数据库反射性能提升,PostgreSQL 快 3 倍,Oracle 快 10 倍。
-
新增对 psycopg 3 和 oracledb 的支持。
这些改动旨在提升性能和现代化使用,但可能需要调整现有代码。建议查看官方迁移指南以确保顺利升级。
详细报告:SQLAlchemy 2.0 相较于 1.4 版本的改动
SQLAlchemy 2.0 是该 Python 数据库工具包的一个重大版本更新,相较于 1.4 版本带来了广泛的 API 调整和新功能。这些变化旨在优化性能、提升现代化特性和简化开发流程,但也可能对现有应用程序的迁移带来一定挑战。以下是详细分析,涵盖核心变化、ORM 调整和新功能,旨在为开发者提供全面的迁移和使用指导。
背景与迁移步骤
SQLAlchemy 2.0 的过渡始于 1.4 版本,提供了逐步迁移的路径。迁移建议包括以下步骤:
-
首先确保应用程序在 SQLAlchemy 1.3 上运行,无 SADeprecationWarning。
-
升级到 1.4,处理 API 和行为上的细微变化(详见 [migration_14.html])。
-
确保使用 Python 3.7 或更高版本,因 2.0 最低支持 3.7。
-
启用 RemovedIn20Warning(通过设置环境变量 SQLALCHEMY_WARN_20=1),解决所有警告,可使用 Python 选项 -W error::DeprecationWarning 获取堆栈跟踪。
-
在 create_engine() 上使用 future=True,以适应 2.0 的 API(如移除隐式自动提交,字符串需用 text())。
-
在 Session 或 sessionmaker 上使用 future=True,更新事务 API(如移除“绑定元数据”,取消 subtransactions)。
-
为 ORM 模型添加 __allow_unmapped__ = True,支持遗留注解(详见 [whatsnew_20.html#whatsnew-20-orm-typing-migration])。
-
最终测试 SQLAlchemy 2.0 版本,关注额外变化(详见 [whatsnew_20.html])。
这些步骤旨在减少迁移中的中断,确保开发者能逐步适应新版本。
核心功能变化
SQLAlchemy 2.0 的核心部分经历了显著调整,影响数据库连接和事务管理:
-
事务管理:移除库级别的自动提交功能。例如,conn.execute() 不再自动提交,需使用 with engine.begin() 或显式调用 conn.commit(),尤其在 future=True 模式下。
-
执行方式:取消“无连接”执行,engine.execute() 被移除,所有操作必须通过 connection.execute() 执行。
-
执行严格性:Connection.execute() 变得更严格,不接受直接字符串 SQL 语句(需用 text()),只支持命名参数,且不支持 *args 或 **kwargs(详见 [core/connections.html#sqlalchemy.engine.Connection])。
-
结果处理:在“未来”模式下,结果行行为类似命名元组,可用 row.keys() 检查键(详见 [migration_14.html#change-result-14-core])。
这些变化要求开发者更明确地管理数据库操作,减少潜在的错误。
SQL 表达式语言调整
SQL 表达式的使用也有更新:
-
select() 现在接受列参数为位置参数,而非关键字参数。例如,select(table.c.x, table.c.y) 替代旧的 select([table.c.x, table.c.y])。
-
DML 语句(如 insert()、update()、delete())不再接受构造函数的关键字参数,需使用生成式方法。例如,insert(table).values(x=10).inline()。
这些调整旨在统一 API 使用,减少歧义。
ORM 配置与使用变化
ORM 部分的变化更为广泛,影响模型定义和查询方式:
-
声明式基础:declarative_base() 现在从 sqlalchemy.orm 导入,而非 sqlalchemy.ext.declarative。
-
映射函数:mapper() 重命名为 registry.map_imperatively(),用于经典映射(详见 [orm/mapping_api.html#sqlalchemy.orm.registry.map_imperatively])。
-
查询方式:Session.query() 被标记为遗留功能,建议使用 Session.execute(select()) 结合 Result.scalars() 获取 ORM 对象。例如,session.execute(select(User)).scalars().all()。
-
主键访问:Session.get() 替代 Query.get(),用于按主键访问对象。
-
连接与加载:join() 和加载选项现在使用属性名而非字符串。例如,join(User.addresses) 替代 join("addresses")。
-
连接链:移除链式连接(如 join("orders", "items")),需逐个调用 join()。
-
别名处理:移除 aliased=True 和 from_joinpoint 参数,需显式使用 aliased()(详见 [orm/queryguide/api.html#sqlalchemy.orm.aliased])。
-
结果去重:ORM 结果行默认不再去重,需用 Result.unique() 处理连接式预加载。例如,session.execute(select(User).options(joinedload(User.addresses))).unique().all()。
-
关系策略:lazy="dynamic" 被 lazy="write_only" 替代,提供不隐式迭代的性能优化,支持异步操作(详见 [whatsnew_20.html#change-7123])。
-
事务模式:移除 Session 的自动提交模式,新增自动开始(autobegin),如 sess.begin() 或首次访问时自动开始。
这些变化旨在统一 ORM 和 Core 的使用模式,提升一致性和性能。
新功能与增强
SQLAlchemy 2.0 引入了多项新功能,提升开发体验和性能:
-
类型支持:深度整合 PEP 484,支持类型驱动的 ORM 声明式风格,类似数据类,无需额外存根。当前为 Beta 级,可能变化(详见 [migration_20.html])。
-
ORM 声明式模型:新增 mapped_column() 替代 Column,支持类型注解用 Mapped,可选择使用 PEP 593 Annotated 配置。迁移步骤包括替换 declarative_base() 为 DeclarativeBase,使用 mapped_column(),应用精确类型 Mapped,移除不必要指令,常用 Annotated(详见 [whatsnew_20.html])。
-
优化批量插入:批量插入操作泛化到除 MySQL 外的所有后端(SQLite、MariaDB、PostgreSQL、Oracle,SQL Server 在 2.0.9 中暂时禁用),支持 RETURNING。性能基准测试(插入 10 万对象)如下:
Driver
|
SQLA 1.4 Time (secs)
|
SQLA 2.0 Time (secs)
|
---|---|---|
sqlite+pysqlite2 (memory)
|
6.204843
|
3.554856
|
postgresql+asyncpg (network)
|
88.292285
|
4.561492
|
postgresql+psycopg (network)
|
N/A (psycopg3)
|
4.861368
|
mssql+pyodbc (network)
|
158.396667
|
4.825139
|
oracle+cx_Oracle (network)
|
92.603953
|
4.809520
|
mariadb+mysqldb (network)
|
71.705197
|
4.075377
|
-
ORM 启用 DML 与 RETURNING:支持 Insert、Update、Delete 使用 Session.execute(),包括批量插入、更新、upsert 和 WHERE RETURNING,synchronize_session 默认“auto”,利用 RETURNING 提升效率(相关票据:#7864、#7865、#8360)。
-
新“只写”关系策略:lazy="write_only" 替代 lazy="dynamic",用 WriteOnlyMapped 注解,支持批量 DML 和 RETURNING(票据:#7123),同时保留 DynamicMapped 支持遗留动态关系。
-
安装与 C 扩展:完全符合 PEP 517,使用 pyproject.toml,C 扩展移植到 Cython,性能提升,预构建在 wheels 中(票据:#7311、#7256)。
-
数据库反射:重构为批量反射,PostgreSQL 快 3 倍,Oracle 快 10 倍(250 表测试:PostgreSQL 1.4 8.2s vs 2.0 3.3s,Oracle 1.4 60.4s vs 2.0 6.8s)。新增 Inspector 方法如 has_schema(),改进缓存,分离 get_view_names() 和 get_materialized_view_names()(票据:#4379)。
-
方言支持:新增 psycopg 3 (psycopg) 和 oracledb 支持(详见 [dialects/postgresql.html#postgresql-psycopg])。
-
条件 DDL:新增 Constraint.ddl_if() 和 Index.ddl_if(),支持条件渲染(票据:#7631)。
-
日期时间字面量渲染:所有后端支持 DATE、TIME、DATETIME 字面量渲染,使用 ISO-8601 和 literal_binds(票据:#5052)。
-
上下文管理器支持:Result 和 AsyncResult 支持上下文管理器,确保游标关闭,适合服务器端游标(票据:#8710)。
-
行为变化:新增 Session.join_transaction_mode 选项("create_savepoint", "conditional_savepoint" 默认),str(engine.url) 默认隐藏密码,Column 替换规则更严格,ORM 声明式列顺序变化(用 mapped_column.sort_order),Sequence 恢复无默认起始值(影响 MS SQL Server),with_variant() 克隆 TypeEngine,Python 除法 (/, //) 跨后端标准化,Session 非法并发访问抛出异常,SQLite 方言对文件数据库使用 QueuePool(2.0.38 也适用于 aiosqlite)(相关票据:#9015、#8567、#8925、#7211、#6980、#4926、#7433、#7490)。
意外细节:性能与兼容性
一个可能出乎意料的细节是,SQLAlchemy 2.0 的批量插入性能提升显著,尤其在网络后端(如 PostgreSQL、Oracle)上,时间从几十秒降至约 5 秒(见上表)。这对高负载应用尤为重要,但需注意 MySQL 后端暂不支持某些优化功能。
结论
SQLAlchemy 2.0 相较于 1.4 版本提供了更现代化的 API 和性能优化,但迁移需谨慎,建议遵循官方文档逐步完成。开发者应特别注意核心事务管理、ORM 查询方式和新增功能的兼容性,以充分利用 2.0 的优势。
关键引用:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?