在项目从本地开发转向线上部署时,很多团队会选择将轻量的SQLite数据库迁移到性能更强的MySQL数据库,下面我们就一步步讲解迁移的具体方法和脚本实现。

迁移前的准备工作
在开始迁移之前,需要先完成以下准备:
- 安装好MySQL服务,创建好目标数据库,确保字符集设置为utf8mb4,避免中文乱码问题
- 安装Python环境,以及需要使用的第三方库:
pymysql用于连接MySQL,sqlite3是Python内置库无需额外安装 - 备份原有的SQLite数据库文件,防止迁移过程中出现数据损坏无法恢复
迁移的核心步骤
整个迁移过程可以分为两个核心部分:表结构迁移和数据迁移,我们分开讲解。
1. 表结构迁移
SQLite和MySQL的字段类型存在差异,需要先做类型映射,常见的映射关系如下:
| SQLite字段类型 | MySQL对应字段类型 |
|---|---|
| INTEGER | INT |
| TEXT | VARCHAR(255) 或 TEXT |
| REAL | DOUBLE |
| BLOB | BLOB |
| DATETIME | DATETIME |
我们可以通过读取SQLite的表结构信息,自动生成MySQL的建表语句,下面是结构迁移的脚本片段:
import sqlite3
import pymysql
# SQLite数据库连接配置
sqlite_conn = sqlite3.connect("source.db")
sqlite_cursor = sqlite_conn.cursor()
# MySQL数据库连接配置
mysql_conn = pymysql.connect(
host="127.0.0.1",
user="root",
password="123456",
database="target_db",
charset="utf8mb4"
)
mysql_cursor = mysql_conn.cursor()
# 获取SQLite中所有表名
sqlite_cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'")
tables = sqlite_cursor.fetchall()
# 类型映射字典
type_map = {
"INTEGER": "INT",
"TEXT": "TEXT",
"REAL": "DOUBLE",
"BLOB": "BLOB",
"DATETIME": "DATETIME"
}
for table in tables:
table_name = table[0]
# 获取表的建表语句
sqlite_cursor.execute(f"SELECT sql FROM sqlite_master WHERE type='table' AND name='{table_name}'")
create_sql = sqlite_cursor.fetchone()[0]
# 替换字段类型
for sqlite_type, mysql_type in type_map.items():
create_sql = create_sql.replace(sqlite_type, mysql_type)
# 执行MySQL建表语句
try:
mysql_cursor.execute(create_sql)
print(f"表 {table_name} 结构迁移完成")
except Exception as e:
print(f"表 {table_name} 结构迁移失败:{e}")2. 数据迁移
结构迁移完成后,就可以迁移表中的数据了,需要注意自增主键和数据编码的问题,下面是数据迁移的脚本:
# 遍历所有表迁移数据
for table in tables:
table_name = table[0]
# 获取表的所有字段
sqlite_cursor.execute(f"PRAGMA table_info({table_name})")
columns = sqlite_cursor.fetchall()
column_names = [col[1] for col in columns]
# 拼接插入语句
placeholders = ",".join(["%s"] * len(column_names))
insert_sql = f"INSERT INTO {table_name} ({','.join(column_names)}) VALUES ({placeholders})"
# 读取SQLite数据
sqlite_cursor.execute(f"SELECT * FROM {table_name}")
rows = sqlite_cursor.fetchall()
# 批量插入MySQL
try:
if rows:
mysql_cursor.executemany(insert_sql, rows)
mysql_conn.commit()
print(f"表 {table_name} 数据迁移完成,共迁移 {len(rows)} 条数据")
else:
print(f"表 {table_name} 没有数据需要迁移")
except Exception as e:
mysql_conn.rollback()
print(f"表 {table_name} 数据迁移失败:{e}")
# 关闭所有连接
sqlite_cursor.close()
sqlite_conn.close()
mysql_cursor.close()
mysql_conn.close()迁移后的验证工作
迁移完成后需要验证数据是否完整:
- 对比两个数据库中每个表的行数是否一致
- 随机抽取部分数据对比字段内容是否相同
- 测试项目连接MySQL后功能是否正常,有没有查询报错的情况
如果遇到字段类型不兼容的问题,可以手动调整类型映射字典,重新执行迁移脚本即可。整个脚本可以根据实际需求扩展,比如增加忽略特定表、处理外键约束等功能。