Python中实现数据库迁移的轻量级方案详解

 更新时间:2026年05月09日 09:44:57   作者:尘埃落定wf  
本文介绍了一套轻量级数据库迁移方案,借鉴了Alembic的核心思想但更加简单易用,该方案通过版本化迁移文件和持久化执行记录,解决了数据库变更管理中的常见痛点,有需要的小伙伴可以了解下

先说问题

项目上线之后,数据库改动是最容易出事的环节。

加一个字段、改一个索引、新建一张表——听起来很小的事,实际操作中经常踩坑:

  • 本地改了,测试环境忘了改
  • 测试改了,生产环境漏了一条 ALTER
  • 多人协作,不知道哪条 SQL 执行过、哪条没执行
  • 出了问题想回溯,根本不知道数据库当时是什么状态

为什么不直接用 Alembic

Alembic 是 Python 生态里最成熟的数据库迁移工具,和 SQLAlchemy 深度集成,功能完整。但用过的人都知道,它有一定的上手门槛:

  • 需要理解 env.pyalembic.ini、版本链等概念
  • autogenerate 自动生成的迁移文件需要仔细审查,生成结果不总是符合预期
  • 对于不用 SQLAlchemy ORM、直接写原生 SQL 的项目,引入 Alembic 反而显得笨重

所以我借鉴了 Alembic 最核心的两个思想——迁移文件版本化执行历史持久化——自己搭了一套更轻的方案:纯 Python + 原生 SQL,没有额外依赖,文件结构一眼看懂,团队新人不需要任何学习成本就能上手。

这篇文章就介绍这套方案的设计思路和具体用法。

它能做什么

一句话:把数据库的每一次结构变更,变成有版本记录、可追溯、不重复执行的代码提交。

具体来说:

  • 每次改表结构,写成迁移文件,提交到代码仓库,和业务代码一起走 Code Review
  • 执行器自动记录哪些迁移跑过了,下次不会重复执行
  • 新同事拉代码,跑一条命令,数据库自动同步到最新状态
  • 多环境(本地 / 测试 / 生产)状态一致,不靠人肉对齐

目录结构

migrations/
  user.py         # users 表迁移
  orders.py       # orders 表迁移
  coupons.py      # coupons 表迁移
migrate.py        # 迁移执行器(项目根目录)

结构很平,没有嵌套。每张表对应一个迁移文件,执行器放在根目录。

迁移文件长什么样

每个迁移文件定义两个东西:要执行的 SQL 列表,和执行后的校验语句。

sql = [
    {
        'id': 1,           # 迁移编号,同一文件内唯一,只增不改
        'sql': """
            DROP TABLE IF EXISTS `orders`;
            CREATE TABLE `orders` (
              `id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
              `order_no` VARCHAR(32) NOT NULL UNIQUE,
              `user_id` INT NOT NULL,
              `total_amount` DECIMAL(12,2) NOT NULL,
              `order_status` TINYINT NOT NULL DEFAULT 0,
              `create_time` DATETIME NOT NULL
            );
        """,
    },
]

checks = [
    'SELECT COUNT(*) FROM `orders`',   # 验证表存在且可查询
]

# ── 执行器兼容格式,请勿修改 ──
migrations = [
    {**item, 'checks': checks}
    for item in sql
]

几个值得注意的设计:

id 只增不改。 每条迁移一旦上线,id 就是它的"身份证",执行器靠它判断是否执行过。改了 id 等于让执行器认不出它,可能重复执行。

新需求追加新条目,不修改旧条目。 要给 orders 表加字段,不是改 id: 1 的 SQL,而是在后面追加 id: 2

sql = [
    { 'id': 1, 'sql': "..." },   # 已执行,保持不动
    {
        'id': 2,
        'sql': """
            ALTER TABLE `orders`
            ADD COLUMN `source` TINYINT DEFAULT 0 COMMENT '订单来源';
        """,
    },
]

这个规则保证迁移历史是线性追加的,任何时间点都能重现数据库状态。

checks 是最后一道保险。 迁移跑完之后,执行器会跑 checks 里的 SQL 做验证。写一条简单的 SELECT COUNT(*) 就够,主要是确认表存在、没有语法错误导致建表失败。

怎么用

查看当前状态——哪些迁移已执行、哪些待执行:

python3 migrate.py --status

执行所有待执行的迁移

python3 migrate.py

执行器会按文件、按 id 顺序跑,跑过的自动跳过,新增的自动执行。

执行记录怎么存

执行器会在数据库里自动创建一张 _migration_history 表,记录每条迁移的执行状态:

字段说明
module迁移文件名(不含 .py),如 orders
migration_id迁移条目的 id
description描述
executed_at执行时间

这张表就是"已执行"的权威记录。下次跑迁移,执行器查这张表,module + migration_id 已存在的全部跳过,只执行新的。

不需要手动维护,不需要记忆,状态完全由工具管理。

这个项目用到的三张表

作为示例,这套迁移方案管理了三张核心业务表:

users(用户表):存用户基本信息和积分,带 added_by / updated_by 审计字段,方便追踪数据是谁改的。

orders(订单主表):覆盖订单全生命周期——从待支付到已完成或已取消,order_status 用 TINYINT 枚举状态,建了组合索引 idx_user_status_time 支持按用户+状态+时间的高频查询。

coupons(优惠券表):支持满减(fixed)和折扣(percent)两种类型,外键关联 users.idmin_amount 字段控制使用门槛。

三张表的结构变更都通过迁移文件管理,任何环境执行 python3 migrate.py 都能同步到一致状态。

新增迁移的完整流程

  1. migrations/ 下找到对应的 .py 文件(或新建一个)
  2. sql 列表末尾追加新条目,id 递增
  3. 运行 python3 migrate.py 执行
# 先看一眼状态,确认预期
python3 migrate.py --status
# 没问题就执行
python3 migrate.py

提交代码时,把迁移文件和业务代码一起提交。其他环境拉代码后跑一遍迁移命令,数据库自动对齐。

和原生 Alembic 的区别

这套方案借鉴了 Alembic 的核心理念,但实现方式更直接:

原生 Alembic这套方案
依赖SQLAlchemy + Alembic纯 Python,无额外依赖
迁移文件自动生成,带版本哈希手写 SQL,结构固定
历史记录alembic_version_migration_history
版本管理链式版本图线性 id 追加
适用场景SQLAlchemy ORM 项目任何用原生 SQL 的项目
上手成本需要理解版本链概念看完本文即可上手

如果你的项目已经深度使用 SQLAlchemy ORM,直接上 Alembic 是更合适的选择。这套方案更适合不用 ORM、直接写 SQL、想要简单可控的迁移流程的场景。

小结

数据库变更管理这件事,越早规范越省事。等到线上出了"某个环境少了个字段"这种问题,排查起来很浪费时间。

这套方案的核心逻辑只有三条:

  1. 变更写成文件,提交到仓库,和代码一起走版本管理
  2. id 只增不改,保证历史可追溯
  3. 执行器自动记录状态,不靠人记忆哪条跑过

结构简单,但把最容易出错的环节都堵住了。

到此这篇关于Python中实现数据库迁移的轻量级方案详解的文章就介绍到这了,更多相关Python数据库迁移内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python matplotlib绘制实时数据动画

    Python matplotlib绘制实时数据动画

    Matplotlib作为Python的2D绘图库,它以各种硬拷贝格式和跨平台的交互式环境生成出版质量级别的图形。本文将利用Matplotlib库绘制实时数据动画,感兴趣的可以了解一下
    2022-03-03
  • 使用Python调取任意数字资产钱包余额功能

    使用Python调取任意数字资产钱包余额功能

    那资产放在钱包的时候,如何来监控余额呢?任何数字资产都可以使用区块浏览器来查询余额,那我们只要从此着手,用Python调取区块浏览器,来查询余额就能实现所有资产的余额监控,感兴趣的朋友跟随小编一起看看吧
    2019-08-08
  • 使用pyecharts无法import Bar的解决方案

    使用pyecharts无法import Bar的解决方案

    这篇文章主要介绍了使用pyecharts无法import Bar的解决方案,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-01-01
  • 利用Python批量保存Excel文件中的图表为图片

    利用Python批量保存Excel文件中的图表为图片

    Excel工作簿作为一款功能强大的数据处理与分析工具,被广泛应用于各种领域,本文将详细介绍如何利用Python自动化实现从Excel文件中提取图表并保存为图片,需要的朋友可以参考下
    2024-06-06
  • Python日志库 Logoru介绍

    Python日志库 Logoru介绍

    Loguru是一个高效且易用的Python日志库,相较于传统的logging模块,它提供了简洁的API、自动化的日志处理、多线程安全等特点,Loguru支持日志级别管理、异常捕获、日志文件轮转与压缩、上下文信息添加等高级功能,感兴趣的朋友跟随小编一起看看吧
    2024-09-09
  • 一文带你了解Python列表生成式应用的八重境界

    一文带你了解Python列表生成式应用的八重境界

    在Python中有非常多且好用的技巧,其中使用最多的是列表生成式,往往可以将复杂的逻辑用简单的语言来实现,本文重点介绍列表生成式应用的八重境界
    2022-09-09
  • python中glom用法的实现

    python中glom用法的实现

    glom是Python库,用于简化嵌套数据操作,支持路径访问、数据转换、容错处理,下面就来介绍一下glom用法,具有一定的参考价值,感兴趣的可以了解一下
    2025-06-06
  • Python中import语句用法案例讲解

    Python中import语句用法案例讲解

    在实际应用中,有时程序所要实现功能比较复杂,代码量也很大,若把所有的代码都存储在一个文件中,则不利于代码的复用和维护,这篇文章主要介绍了Python中import语句用法详解,需要的朋友可以参考下
    2022-12-12
  • python实现PID算法及测试的例子

    python实现PID算法及测试的例子

    今天小编就为大家分享一篇python实现PID算法及测试的例子,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-08-08
  • Dijkstra算法详细介绍及Python实现方法

    Dijkstra算法详细介绍及Python实现方法

    迪杰斯特拉(Dijkstra)算法是一种用于寻找有向图中单源最短路径的经典算法,在这个算法中,我们从一个源节点开始,逐步扩展最短路径到其他节点,直到到达所有节点或者目标节点,这篇文章主要介绍了Dijkstra算法详细介绍及Python实现的相关资料,需要的朋友可以参考下
    2026-03-03

最新评论