
1. Flask数据库操作基础概念Flask作为轻量级Python Web框架数据库操作是其核心功能之一。与Django自带ORM不同Flask需要借助扩展来实现数据库交互这种设计既保持了核心简洁又提供了灵活的扩展选择。我刚开始用Flask时最困惑的就是SQLAlchemy和Flask-SQLAlchemy的区别。简单来说SQLAlchemy是独立ORM工具而Flask-SQLAlchemy是其Flask集成版本提供了更适合Web开发的封装。比如上下文管理、分页支持等Web开发常用功能。数据库连接的核心流程可以概括为建立连接配置URI格式创建模型类映射数据库表通过会话(Session)执行CRUD操作处理事务提交或回滚重要提示生产环境务必使用连接池直接创建连接会导致性能问题。SQLAlchemy默认就带有连接池机制。2. 环境配置与初始化2.1 安装必要依赖基础环境需要以下包pip install flask flask-sqlalchemy pymysql这里我推荐使用pymysql作为MySQL驱动比默认的mysql-connector更稳定。如果是PostgreSQL则需要psycopg2。2.2 配置数据库URI在config.py中配置典型格式class Config: SQLALCHEMY_DATABASE_URI mysqlpymysql://user:passwordhost:port/dbname SQLALCHEMY_TRACK_MODIFICATIONS False # 避免警告 SQLALCHEMY_ECHO True # 调试时显示SQLURI格式解析mysqlpymysql:// 表示使用MySQL数据库和pymysql驱动user:password 是数据库账号密码host:port 数据库服务器地址/dbname 指定具体数据库2.3 初始化Flask-SQLAlchemy在工厂函数中初始化from flask_sqlalchemy import SQLAlchemy db SQLAlchemy() def create_app(): app Flask(__name__) app.config.from_object(Config) db.init_app(app) return app这种模式支持多应用实例共享同一个db对象是Flask推荐的做法。3. 数据模型定义实战3.1 基础模型示例典型的用户模型定义class User(db.Model): __tablename__ users # 显式指定表名 id db.Column(db.Integer, primary_keyTrue) username db.Column(db.String(80), uniqueTrue, nullableFalse) email db.Column(db.String(120), uniqueTrue) created_at db.Column(db.DateTime, defaultdatetime.utcnow) def __repr__(self): return fUser {self.username}字段类型说明Integer: 整数String(长度): 字符串DateTime: 日期时间Boolean: 布尔值Float: 浮点数3.2 高级字段选项字段常用参数name db.Column(db.String(100), indexTrue, # 创建索引 nullableFalse, # 非空 defaultanonymous, # 默认值 server_defaultguest) # 数据库端默认值3.3 关系建模一对多关系示例class Post(db.Model): id db.Column(db.Integer, primary_keyTrue) author_id db.Column(db.Integer, db.ForeignKey(users.id)) author db.relationship(User, backrefposts)多对多关系需要关联表tags db.Table(post_tags, db.Column(post_id, db.Integer, db.ForeignKey(post.id)), db.Column(tag_id, db.Integer, db.ForeignKey(tag.id)) ) class Post(db.Model): tags db.relationship(Tag, secondarytags, backrefposts)4. 数据库操作全解析4.1 创建表在Flask shell中执行flask shell db.create_all()实际项目中更推荐使用迁移工具Alembicpip install flask-migrate初始化迁移环境from flask_migrate import Migrate migrate Migrate(app, db)然后执行flask db init flask db migrate -m initial migration flask db upgrade4.2 CRUD操作创建记录new_user User(usernamejohn, emailjohnexample.com) db.session.add(new_user) db.session.commit()查询记录# 获取全部 users User.query.all() # 条件查询 user User.query.filter_by(usernamejohn).first() # 复杂查询 admins User.query.filter( User.username.like(%admin%), User.created_at datetime(2023,1,1) ).order_by(User.created_at.desc()).limit(10)更新记录user User.query.get(1) user.email newexample.com db.session.commit()删除记录user User.query.get(1) db.session.delete(user) db.session.commit()4.3 事务处理事务的基本模式try: db.session.begin() # 多个操作 db.session.commit() except: db.session.rollback() raiseFlask-SQLAlchemy会自动在每个请求结束时提交会话可以通过以下配置关闭app.config[SQLALCHEMY_COMMIT_ON_TEARDOWN] False5. 性能优化实践5.1 查询优化技巧避免N1查询# 不好的写法 posts Post.query.all() for post in posts: print(post.author.username) # 每次循环都查询author # 好的写法 - 使用joinedload from sqlalchemy.orm import joinedload posts Post.query.options(joinedload(Post.author)).all()只选择需要的字段users db.session.query(User.id, User.username).all()使用原生SQL优化复杂查询result db.session.execute( SELECT username, COUNT(posts.id) FROM users LEFT JOIN posts ON users.id posts.user_id GROUP BY users.id )5.2 连接池配置生产环境推荐配置app.config[SQLALCHEMY_ENGINE_OPTIONS] { pool_size: 20, max_overflow: 10, pool_timeout: 30, pool_recycle: 3600 # 1小时回收连接 }5.3 索引策略模型定义时添加索引class User(db.Model): __table_args__ ( db.Index(idx_username_email, username, email), )6. 常见问题排查6.1 连接问题错误OperationalError: (pymysql.err.OperationalError) (2003, Cant connect to MySQL server)解决方案检查数据库服务是否运行确认防火墙设置验证连接参数是否正确6.2 编码问题错误1366, Incorrect string value需要在URI中指定编码SQLALCHEMY_DATABASE_URI mysqlpymysql://...?charsetutf8mb46.3 会话管理错误SQLAlchemy DetachedInstanceError这是因为对象与会话分离后访问延迟加载的属性。解决方案在需要时重新关联会话使用expire_on_commitFalse配置db.session.expire_on_commit False7. 生产环境最佳实践7.1 多数据库支持配置读写分离SQLALCHEMY_BINDS { master: mysql://master, slave: mysql://slave } class User(db.Model): __bind_key__ master # 默认写操作7.2 监控与日志配置慢查询日志from sqlalchemy import event from sqlalchemy.engine import Engine import time event.listens_for(Engine, before_cursor_execute) def before_cursor_execute(conn, cursor, statement, parameters, context, executemany): context._query_start_time time.time() event.listens_for(Engine, after_cursor_execute) def after_cursor_execute(conn, cursor, statement, parameters, context, executemany): duration time.time() - context._query_start_time if duration 0.5: # 记录超过500ms的查询 app.logger.warning(fSlow query: {statement} took {duration:.2f}s)7.3 测试策略使用内存数据库测试class TestConfig(Config): SQLALCHEMY_DATABASE_URI sqlite:///:memory: TESTING TruePytest夹具示例import pytest pytest.fixture def db_session(app): with app.app_context(): db.create_all() yield db.session db.session.remove() db.drop_all()