HarmonyOS RDB 数据迁移实战:建表升级、事务保护与回滚验证
HarmonyOS RDB 数据迁移实战:建表升级、事务保护与回滚验证
RDB 真正难的不是 create table,而是版本升级。用户从旧版本直接升级到新版本时,表结构、索引、默认值和历史数据都要一起过关;任何一步失败,都可能导致启动卡死或数据丢失。本文用路线收藏表从 v1 升到 v2 的场景,写一套可回滚、可验证的迁移链路。

本文先把迁移失败场景讲清
迁移文章要解决的是升级路径,而不是孤立 SQL。读者需要知道每个版本做了什么、失败后如何回滚、升级后如何证明数据还在。
- StoreConfig 固定,避免配置漂移。
- 按当前版本顺序执行迁移。
- 迁移过程放进事务保护。
- 升级后跑结构和数据校验。
RDB 资料与声明入口
| 项目 | 内容 |
|---|---|
| 本地声明 | D:/harmonyos/SDK/23/ets/api/@ohos.data.relationalStore.d.ts |
| 核心 API | getRdbStore、executeSql、beginTransaction、commit、rollBack。 |
| 异常线索 | StoreConfig 变化可能触发 14800017。 |
| 关闭边界 | ResultSet 与 RdbStore 需要按生命周期关闭。 |
关系存储的版本边界
| 项目 | 内容 |
|---|---|
| SDK | HarmonyOS SDK 23。 |
| 数据库 | trail.db,示例版本从 1 升到 2。 |
| 场景 | 路线收藏、离线轨迹索引、搜索字段补充。 |
| 边界 | 大文件和图片不建议直接存入关系表。 |


数据库配置不能随意改
数据库名、加密、存储目录等配置一旦发布就要谨慎调整。配置变化可能让 getRdbStore 失败。
import relationalStore from '@ohos.data.relationalStore';
export const TrailDbConfig: relationalStore.StoreConfig = {
name: 'trail.db',
securityLevel: relationalStore.SecurityLevel.S1
};
export const TrailDbVersion = 2;
配置文件是数据库入口边界。版本号单独声明,便于启动后和 store.version 比较。
建表 SQL 要具备幂等性
初始化表结构使用 IF NOT EXISTS,避免重复启动或测试环境重建时失败。
export const CreateFavoriteRouteSql = `
CREATE TABLE IF NOT EXISTS favorite_route (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
city TEXT NOT NULL,
created_at INTEGER NOT NULL
)`;
export const CreateFavoriteIndexSql = `
CREATE INDEX IF NOT EXISTS idx_favorite_city ON favorite_route(city)`;
建表和索引分开声明。后续迁移可以精确知道哪些结构已经存在。
打开数据库后立即执行版本检查
不要等页面查询失败后再迁移。应用启动打开 RDB 后,先补齐结构再暴露仓储能力。
export async function openTrailStore(context: Context): Promise<relationalStore.RdbStore> {
const store = await relationalStore.getRdbStore(context, TrailDbConfig);
await store.executeSql(CreateFavoriteRouteSql);
await store.executeSql(CreateFavoriteIndexSql);
await migrateTrailDb(store, store.version, TrailDbVersion);
store.version = TrailDbVersion;
return store;
}
打开函数负责结构准备。业务仓储拿到 store 时,表结构已经处于目标版本。
迁移用事务包起来
v2 给收藏路线增加 difficulty 字段,并回填默认值。字段增加和数据回填要么一起成功,要么一起回滚。
async function migrateTrailDb(store: relationalStore.RdbStore, from: number, to: number): Promise<void> {
if (from < 2 && to >= 2) {
store.beginTransaction();
try {
await store.executeSql('ALTER TABLE favorite_route ADD COLUMN difficulty TEXT DEFAULT "normal"');
await store.executeSql('UPDATE favorite_route SET difficulty = "normal" WHERE difficulty IS NULL');
store.commit();
} catch (err) {
store.rollBack();
throw err;
}
}
}
事务把结构变化和数据回填绑在一起。失败时抛出异常,启动层可以给出修复提示或降级策略。
插入数据前做实体校验
RDB 不应该替业务兜所有错误。仓储层先校验必填字段,再执行 SQL。
export interface FavoriteRouteEntity {
id: string;
title: string;
city: string;
createdAt: number;
difficulty: 'easy' | 'normal' | 'hard';
}
function assertFavorite(route: FavoriteRouteEntity): void {
if (!route.id || !route.title || !route.city) {
throw new Error('favorite route fields are required');
}
}
实体校验阻止坏数据进入数据库。SQL 约束和业务校验一起工作,问题更早暴露。
查询后关闭 ResultSet
结果集不关闭,长时间使用后可能积累资源问题。查询函数应在 finally 中 close。
async function countFavorites(store: relationalStore.RdbStore): Promise<number> {
const result = await store.querySql('SELECT COUNT(1) AS total FROM favorite_route');
try {
result.goToFirstRow();
return result.getLong(result.getColumnIndex('total'));
} finally {
result.close();
}
}
查询函数只返回业务值,不泄漏 ResultSet。finally 保证异常路径也能释放。
升级后跑结构验收 SQL
迁移完成不代表正确。至少查询字段、索引和样本数据,确认新字段存在且旧数据还在。
async function verifyV2(store: relationalStore.RdbStore): Promise<void> {
await store.executeSql('SELECT difficulty FROM favorite_route LIMIT 1');
const total = await countFavorites(store);
console.info(`[TrailDb] v2 verify total=${total}`);
}
验收 SQL 是迁移后的证据。它能在开发和灰度阶段尽早发现漏迁移。
迁移验证流程:从旧库样本升级到新结构
RDB 迁移建议准备三类样本:空库、只有 v1 表结构的旧库、包含多条真实收藏数据的旧库。升级后分别确认数据库能打开、difficulty 字段存在、旧数据条数不变、索引查询仍然可用。灰度前还要模拟迁移中途抛错,确认事务回滚后不会留下半截字段或半截数据。
async function verifyFavoriteMigration(store: relationalStore.RdbStore): Promise<void> {
await verifyV2(store);
const total = await countFavorites(store);
if (total < 0) {
throw new Error('favorite count is invalid');
}
}
验证入口复用前面的结构检查和数量检查。它不修改业务数据,只证明迁移后的库可以被仓储层继续使用。
HarmonyOS RDB 数据迁移实战排查表
| 现象 | 优先查看 | 处理方式 |
|---|---|---|
| 升级后启动失败 | StoreConfig 是否变化 | 保持数据库配置稳定,必要时设计专门迁移。 |
| 新增字段查询失败 | ALTER TABLE 是否执行 | 检查 store.version 和迁移顺序。 |
| 旧收藏丢失 | 迁移是否直接重建表 | 优先 ALTER 和回填,避免 DROP。 |
| 内存占用异常 | ResultSet 是否 close | 查询函数使用 finally 关闭。 |
HarmonyOS RDB 数据迁移实战验收清单
上线或交付前建议逐项确认,尤其是生命周期、异常分支和数据一致性。
- StoreConfig 发布后保持稳定。
- 每个版本迁移都有明确 SQL。
- 结构变化和数据回填在事务内完成。
- 升级后执行结构和样本数据验收。
- ResultSet 与 RdbStore 生命周期清楚。
小结
RDB 迁移要把用户已有数据放在第一位。建表、升级、回填、验证和关闭资源都写清楚,数据库版本升级才不会成为线上事故入口。
参考资料
以下资料用于核对 API 名称和能力边界,落地时请结合项目目标 API 版本复核。
- HarmonyOS SDK 23 本地 API 声明:@ohos.data.relationalStore.d.ts
更多推荐




所有评论(0)