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())。
  • Sessionsessionmaker 上使用 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=Truefrom_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:支持 InsertUpdateDelete 使用 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)。
  • 上下文管理器支持ResultAsyncResult 支持上下文管理器,确保游标关闭,适合服务器端游标(票据:#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 的优势。
关键引用:
posted @   John-Python  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示