Python与数据库:SQLAlchemy实战指南
数据库操作是后端开发最核心的部分之一。在Python中直接写原生SQL虽然灵活但在项目变得复杂后ORM对象关系映射能帮我们节省大量时间。SQLAlchemy是Python生态中最强大的ORM框架这篇文章不讲太深的理论直接分享实际项目中最常用的操作和技巧。一、为什么选择SQLAlchemyPython的ORM有好几个选择但SQLAlchemy是公认的工业级解决方案。SQLAlchemy的核心优势支持多种数据库PostgreSQL、MySQL、SQLite、Oracle等提供了两种使用方式CoreSQL表达式和ORM对象映射性能优秀SQL生成高效连接池管理完善支持异步1.4版本对比其他ORM特性SQLAlchemyDjango ORMpeewee独立使用✅❌需要Django✅多数据库支持完整基本支持基本支持SQL生成能力极强中等中等学习曲线陡峭平缓平缓灵活性极高中等中等二、基础模型定义和连接配置首先安装bashpip install sqlalchemy # 根据使用的数据库安装对应驱动 pip install psycopg2-binary # PostgreSQL pip install pymysql # MySQL pip install aiomysql # MySQL异步驱动基础配置pythonfrom sqlalchemy import create_engine, Column, Integer, String, DateTime, Boolean, Text from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship from datetime import datetime # 创建数据库引擎 # 格式: 数据库类型://用户名:密码主机:端口/数据库名 engine create_engine( postgresql://user:passwordlocalhost:5432/mydb, echoTrue, # 打印生成的SQL调试时很有用 pool_size10, # 连接池大小 max_overflow20, # 连接池最大溢出数 pool_recycle3600, # 连接回收时间秒 pool_pre_pingTrue, # 使用前检测连接是否有效 ) # 创建基类 Base declarative_base() # 创建会话工厂 SessionLocal sessionmaker(autocommitFalse, autoflushFalse, bindengine)定义模型pythonfrom sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Float, Text, Boolean from sqlalchemy.orm import relationship from datetime import datetime class User(Base): __tablename__ users id Column(Integer, primary_keyTrue, indexTrue) username Column(String(50), uniqueTrue, nullableFalse, indexTrue) email Column(String(100), uniqueTrue, nullableFalse) password_hash Column(String(200), nullableFalse) full_name Column(String(100)) age Column(Integer) is_active Column(Boolean, defaultTrue) created_at Column(DateTime, defaultdatetime.utcnow) updated_at Column(DateTime, defaultdatetime.utcnow, onupdatedatetime.utcnow) # 关系 orders relationship(Order, back_populatesuser, cascadeall, delete-orphan) def __repr__(self): return fUser(id{self.id}, username{self.username}) class Product(Base): __tablename__ products id Column(Integer, primary_keyTrue, indexTrue) name Column(String(200), nullableFalse) description Column(Text) price Column(Float, nullableFalse) stock Column(Integer, default0) category Column(String(50)) created_at Column(DateTime, defaultdatetime.utcnow) class Order(Base): __tablename__ orders id Column(Integer, primary_keyTrue, indexTrue) user_id Column(Integer, ForeignKey(users.id), nullableFalse) product_id Column(Integer, ForeignKey(products.id), nullableFalse) quantity Column(Integer, nullableFalse) total_amount Column(Float, nullableFalse) status Column(String(20), defaultpending) # pending, paid, shipped, completed, cancelled created_at Column(DateTime, defaultdatetime.utcnow) # 关系 user relationship(User, back_populatesorders) product relationship(Product) # 创建表 Base.metadata.create_all(engine)三、CRUD操作最常用的增删改查创建记录pythonfrom sqlalchemy.orm import Session def create_user(db: Session, username: str, email: str, password_hash: str): 创建用户 user User( usernameusername, emailemail, password_hashpassword_hash, created_atdatetime.utcnow() ) db.add(user) db.commit() db.refresh(user) # 刷新获取生成的id return user # 批量创建 def create_users_bulk(db: Session, users_data: list): 批量创建用户 users [User(**data) for data in users_data] db.add_all(users) db.commit() return users # 使用 with SessionLocal() as db: user create_user(db, zhangsan, zhangsanexample.com, hashed_password) print(user.id)查询记录pythonfrom sqlalchemy import and_, or_, not_, desc, func def get_user_by_id(db: Session, user_id: int): 根据ID获取用户 return db.query(User).filter(User.id user_id).first() def get_user_by_username(db: Session, username: str): 根据用户名获取用户 return db.query(User).filter(User.username username).first() def get_active_users(db: Session, skip: int 0, limit: int 100): 获取活跃用户列表 return db.query(User).filter(User.is_active True)\ .offset(skip).limit(limit).all() def search_users(db: Session, keyword: str): 搜索用户模糊匹配 return db.query(User).filter( or_( User.username.like(f%{keyword}%), User.email.like(f%{keyword}%), User.full_name.like(f%{keyword}%) ) ).all() def get_users_with_orders(db: Session): 获取有订单的用户使用join return db.query(User).join(Order).distinct().all() def get_user_statistics(db: Session): 获取用户统计信息聚合查询 total_users db.query(func.count(User.id)).scalar() active_users db.query(func.count(User.id)).filter(User.is_active True).scalar() avg_age db.query(func.avg(User.age)).scalar() return { total: total_users, active: active_users, avg_age: avg_age or 0 }更新记录pythondef update_user(db: Session, user_id: int, **kwargs): 更新用户信息 user db.query(User).filter(User.id user_id).first() if user: for key, value in kwargs.items(): if hasattr(user, key): setattr(user, key, value) user.updated_at datetime.utcnow() db.commit() db.refresh(user) return user def update_users_bulk(db: Session, user_ids: list, updates: dict): 批量更新用户 db.query(User).filter(User.id.in_(user_ids)).update( updates, synchronize_sessionFalse ) db.commit() # 使用 with SessionLocal() as db: # 单个更新 user update_user(db, 1, full_name张三丰, age30) # 批量更新 update_users_bulk(db, [1, 2, 3], {is_active: False})删除记录pythondef delete_user(db: Session, user_id: int): 删除用户软删除标记为不活跃 user db.query(User).filter(User.id user_id).first() if user: user.is_active False db.commit() return True return False def delete_user_permanent(db: Session, user_id: int): 永久删除用户 user db.query(User).filter(User.id user_id).first() if user: db.delete(user) db.commit() return True return False def delete_inactive_users(db: Session): 批量删除不活跃用户 deleted_count db.query(User).filter(User.is_active False).delete() db.commit() return deleted_count四、高级查询技巧复杂条件查询pythonfrom sqlalchemy import and_, or_, not_, between, in_ def complex_query(db: Session, filters: dict): 复杂条件查询 query db.query(User) # 组合条件 conditions [] if filters.get(min_age): conditions.append(User.age filters[min_age]) if filters.get(max_age): conditions.append(User.age filters[max_age]) if filters.get(username_like): conditions.append(User.username.like(f%{filters[username_like]}%)) if filters.get(active_only): conditions.append(User.is_active True) if filters.get(exclude_ids): conditions.append(not_(User.id.in_(filters[exclude_ids]))) if conditions: query query.filter(and_(*conditions)) return query.all()排序和分页pythonfrom sqlalchemy import desc, asc def paginated_query(db: Session, page: int 1, page_size: int 20, sort_by: str id, sort_order: str desc): 分页查询 # 计算偏移量 offset (page - 1) * page_size # 排序方向 order_func desc if sort_order desc else asc # 获取排序字段 sort_field getattr(User, sort_by, User.id) # 查询 query db.query(User).order_by(order_func(sort_field)) # 获取总数 total query.count() # 获取当前页数据 items query.offset(offset).limit(page_size).all() return { items: items, total: total, page: page, page_size: page_size, total_pages: (total page_size - 1) // page_size }子查询和复杂查询pythonfrom sqlalchemy import func, select def get_users_with_high_value_orders(db: Session, min_amount: float 1000): 获取有高额订单的用户子查询 subquery db.query(Order.user_id).filter(Order.total_amount min_amount).subquery() return db.query(User).filter(User.id.in_(subquery)).all() def get_order_statistics(db: Session): 订单统计分组查询 result db.query( User.username, func.count(Order.id).label(order_count), func.sum(Order.total_amount).label(total_amount), func.avg(Order.total_amount).label(avg_amount) ).join(Order, User.id Order.user_id)\ .group_by(User.id, User.username)\ .order_by(desc(total_amount))\ .all() return result五、事务管理pythonfrom sqlalchemy.exc import IntegrityError, SQLAlchemyError def transfer_order(db: Session, from_user_id: int, to_user_id: int, order_id: int): 转移订单事务示例 try: # 开始事务with块自动管理 with db.begin(): # 获取订单 order db.query(Order).filter(Order.id order_id).first() if not order: raise ValueError(订单不存在) # 更新订单所属用户 order.user_id to_user_id # 记录操作日志假设有日志表 # log OperationLog(...) # db.add(log) # 所有操作都成功才提交 # with块结束时会自动commit return True except IntegrityError as e: db.rollback() print(f数据完整性错误: {e}) return False except SQLAlchemyError as e: db.rollback() print(f数据库错误: {e}) return False # 更复杂的嵌套事务 def complex_transaction(db: Session): 复杂事务示例 try: # 方式1显式管理 db.begin_nested() # 保存点 try: # 执行一些操作 user db.query(User).filter(User.id 1).first() user.is_active False # 如果这里出错只会回滚到这个保存点 db.begin_nested() try: # 更细粒度的操作 order db.query(Order).filter(Order.id 1).first() order.status cancelled except Exception: db.rollback() # 回滚到第二个保存点 except Exception: db.rollback() # 回滚到第一个保存点 else: db.commit() except Exception as e: db.rollback() print(f事务失败: {e})六、性能优化技巧1. 使用selectinload避免N1查询pythonfrom sqlalchemy.orm import selectinload, joinedload # ❌ 错误方式N1查询 def get_orders_naive(db: Session): orders db.query(Order).all() for order in orders: # 每次访问order.user都会触发一次查询 print(order.user.username) # N次额外查询 # ✅ 正确方式预加载关联数据 def get_orders_optimized(db: Session): orders db.query(Order).options( selectinload(Order.user), # 一次查询加载所有用户 joinedload(Order.product) # 使用JOIN加载商品 ).all() for order in orders: print(order.user.username) # 不会触发额外查询2. 只查询需要的字段python# ❌ 查询所有字段 def get_all_users_fields(db: Session): return db.query(User).all() # ✅ 只查询需要的字段 def get_user_names_only(db: Session): return db.query(User.id, User.username, User.email).all() # 返回字典而不是对象 def get_user_dicts(db: Session): return db.query(User.id, User.username).all() # 返回命名元组列表3. 使用批量操作python# ❌ 逐条插入 def insert_users_one_by_one(db: Session, users_data: list): for data in users_data: user User(**data) db.add(user) db.commit() # ✅ 批量插入 def insert_users_bulk(db: Session, users_data: list): db.bulk_insert_mappings(User, users_data) db.commit()4. 合理使用索引pythonfrom sqlalchemy import Index # 在模型上定义索引 class User(Base): __tablename__ users id Column(Integer, primary_keyTrue) username Column(String(50)) email Column(String(100)) age Column(Integer) city Column(String(50)) # 复合索引 __table_args__ ( Index(idx_username_age, username, age), Index(idx_city_email, city, email), )七、异步SQLAlchemySQLAlchemy 1.4 支持异步操作配合FastAPI非常实用pythonfrom sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker from sqlalchemy import select # 创建异步引擎 async_engine create_async_engine( postgresqlasyncpg://user:passwordlocalhost:5432/mydb, echoTrue, pool_size10, ) # 异步会话工厂 AsyncSessionLocal sessionmaker( async_engine, class_AsyncSession, expire_on_commitFalse, ) # 异步CRUD async def get_user_async(user_id: int): async with AsyncSessionLocal() as db: result await db.execute( select(User).where(User.id user_id) ) return result.scalar_one_or_none() async def create_user_async(user_data: dict): async with AsyncSessionLocal() as db: user User(**user_data) db.add(user) await db.commit() await db.refresh(user) return user # 在FastAPI中使用 from fastapi import FastAPI app FastAPI() app.get(/users/{user_id}) async def get_user(user_id: int): user await get_user_async(user_id) if not user: return {error: User not found} return {id: user.id, username: user.username}八、常见问题与解决方案1. 连接池耗尽python# 增加连接池大小 engine create_engine( postgresql://..., pool_size20, # 基础连接数 max_overflow30, # 最大额外连接数 pool_pre_pingTrue, # 自动重连 )2. 数据库连接超时python# 设置连接超时和回收 engine create_engine( postgresql://..., connect_args{connect_timeout: 10}, pool_recycle3600, # 一小时后回收连接 )3. 查询性能慢使用explain()查看执行计划pythonfrom sqlalchemy import text def explain_query(db: Session): query db.query(User).filter(User.age 18) # 打印SQL print(str(query)) # 执行EXPLAIN result db.execute( text(fEXPLAIN ANALYZE {str(query)}) ) for row in result: print(row)总结SQLAlchemy功能强大但学习曲线确实陡峭。刚入门的朋友可以从核心功能开始逐步深入。学习建议先熟悉CRUD基础操作掌握查询过滤和排序学会处理关系映射了解性能优化技巧再研究高级特性记住SQLAlchemy的目标不是让你忘记SQL而是让SQL操作更安全、更高效。在复杂查询时有时候直接写原生SQL反而更清晰。

相关新闻

死亡细胞修改器下载 及其用法

死亡细胞修改器下载 及其用法

下载链接 转存 避免丢失 《死亡细胞》风灵月影修改器:技术解析与功能详解 《死亡细胞》(Dead Cells)作为一款将Roguelite与银河恶魔城机制融合的硬核动作游戏,以其流畅的战斗、严苛的死亡惩罚和丰富的武器构筑受到核心玩家喜爱。…

2026/7/23 18:06:25 阅读更多 →
左上角角标NEW、最新CSS代码

左上角角标NEW、最新CSS代码

demo <!DOCTYPE html> <html><head><style>/*角标签&#xff0c;父元素必须设置position: relative;overflow: hidden;height: 大于120;width: 大于120px;&#xff0c;同时&#xff0c;角标标签内加入属性superscriptTitle"左上角标签文字内容&q…

2026/7/23 18:06:25 阅读更多 →
嵌入式以太网MAC中断与地址过滤:寄存器级配置与实战避坑指南

嵌入式以太网MAC中断与地址过滤:寄存器级配置与实战避坑指南

1. 项目概述与核心价值 在嵌入式网络开发中&#xff0c;尤其是基于MCU的以太网应用&#xff0c;直接操作硬件寄存器往往是实现高性能、低延迟通信的必经之路。很多开发者习惯于依赖现成的驱动库或HAL&#xff08;硬件抽象层&#xff09;&#xff0c;这确实能快速上手&#xff0…

2026/7/23 18:06:25 阅读更多 →

最新新闻

出差拜访客户攒了好几份录音 2026百度音频转文字免费版够用吗

出差拜访客户攒了好几份录音 2026百度音频转文字免费版够用吗

先回答用户真正关心的问题 根据我2025年底对2026版本的试用&#xff0c;结论很明确&#xff1a;如果你只需要转单条1小时以内、音质清晰、普通话标准的客户拜访录音&#xff0c;只要纯文字&#xff0c;百度音频转文字免费版够用。但如果你出差攒了好几份长录音&#xff0c;要提…

2026/7/23 18:20:29 阅读更多 →
2026最新:语音转文字在线生成怎么选?3款免费实用工具亲测好用

2026最新:语音转文字在线生成怎么选?3款免费实用工具亲测好用

先回答用户真正关心的问题 现在2026年找免费实用的语音转文字在线生成工具&#xff0c;不需要乱搜乱试&#xff0c;我作为长期测试AI效率工具的博主&#xff0c;亲测了三款不同场景下都好用的工具&#xff0c;你可以直接按需求对号入座&#xff1a;纯实时听写选Nerd Dictation…

2026/7/23 18:20:29 阅读更多 →
2026年怎么选高性价比ai读文字工具:零成本日均省12分钟工作

2026年怎么选高性价比ai读文字工具:零成本日均省12分钟工作

先回答用户真正关心的问题 2026年选高性价比AI读文字工具&#xff0c;核心要匹配职场新人快速掌握岗位知识的需求&#xff0c;零成本前提下优先按场景选&#xff1a;仅做临时转写选基础免费工具&#xff0c;需要整理复习卡片选带知识整理功能的工具&#xff0c;按照可复现的标…

2026/7/23 18:20:29 阅读更多 →
界面控件Telerik UI for ASP. NET Core教程 - 如何为网格添加上下文菜单?

界面控件Telerik UI for ASP. NET Core教程 - 如何为网格添加上下文菜单?

Telerik UI for ASP. NET Core是用于跨平台响应式Web和云开发的最完整的UI工具集&#xff0c;拥有超过60个由Kendo UI支持的ASP.NET核心组件。它的响应式和自适应的HTML5网格&#xff0c;提供从过滤、排序数据到分页和分层数据分组等100多项高级功能。上下文菜单允许开发者为应…

2026/7/23 18:20:29 阅读更多 →
WinForm应用实战开发指南 - 如何实现工具栏/菜单的动态呈现?

WinForm应用实战开发指南 - 如何实现工具栏/菜单的动态呈现?

在Winform系统开发中&#xff0c;为了对系统的工具栏/菜单进行动态的控制&#xff0c;我们对系统的工具栏/菜单进行动态配置&#xff0c;这样可以把系统的功能弹性发挥到极致。通过动态工具栏/菜单的配置方式&#xff0c;我们可以很容易的为系统新增所需的功能&#xff0c;通过…

2026/7/23 18:20:29 阅读更多 →
界面控件DevExpress ASP.NET富文本编辑器 - 快速集成高级文本编辑功能

界面控件DevExpress ASP.NET富文本编辑器 - 快速集成高级文本编辑功能

从DOCx和RTF到EPUB&#xff0c;DevExpress ASP. NET Rich Text Editor&#xff08;富文本编辑器&#xff09;(WYSIWYG文字处理器)提供了用户所需的功能&#xff0c;可以在下一个Web应用程序中快速合并高级文本编辑功能。P.S&#xff1a;DevExpress ASP.NET Web Forms Controls拥…

2026/7/23 18:19:29 阅读更多 →

日新闻

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;从单点好评到指数级传播&#xff1a;AI副业主理人必须掌握的4层口碑渗透模型&#xff08;含ROI测算表&#xff09; 当AI副业主理人不再仅满足于单次服务交付&#xff0c;而是主动构建可复用、可裂变、可…

2026/7/23 0:00:25 阅读更多 →
AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;AI写作开头钩子设计&#xff1a;为什么你的AI文案完读率不足18%&#xff1f;——基于2,346篇A/B测试报告的归因分析 在对2,346篇跨行业AI生成文案的A/B测试数据进行聚类分析后&#xff0c;我们发现&#xff1…

2026/7/23 0:01:26 阅读更多 →
Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南&#xff1a;免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/23 0:01:26 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中&#xff0c;我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源&#xff0c;还是配置文件、证书等&#xff0c;都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下&#xff0c;但这…

2026/7/22 8:58:19 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP&#xff08;轻量级目录访问协议&#xff09;作为企业级身份认证的黄金标准&#xff0c;已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时&#xff0c;发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/22 19:43:43 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”&#xff0c;而是以可解释、可审计、可迭代的方式&#xff0c;赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 17:49:47 阅读更多 →

月新闻