iOS SDK 开发 -- 数据库版本迁移方案

一般来说,具有持久层的SDK(或 App)都会附带着有版本迁移的需求,但数据迁移实现起来还是比较简单,下面简单地分析下:

迁移方法

数据库迁移,并不是直接删除数据库再创建这么简单,需要考虑的主要是在迁移的同时保留用户原来的数据内容。

在做数据库迁移前需要考虑的几个问题:

  1. 是直接安装新版本(不涉及数据迁移问题)还是从旧版本迁移过来的;
  2. 用户在用的是版本1,还是版本2,还是版本xxx;
  3. 迁移的操作应该放在哪里;

问题1:所有创建数据库的代码都是最新结构的代码,因为直接安装新版本是不存在数据迁移的问题,要做的把从旧版本升级上来的表结构保持和新版本的一致,并且保留原来的内容,或者更新你需要更新的内容。

问题2:如果用户没有及时更新,错过了好几个版本的数据库升级,那么数据库的升级需要一步步的向上升级,比如最新版本是 V4,当前用户的版本是 V2,升级顺序应该是 V2 -> V3 -> V4。

问题3:应用应该放在 didFinishLaunching,SDK 应该放在启动的方法里面。

了解上面三个问题后,可以大概了解数据库迁移需要关注的东西有哪些了,接下来说下迁移的思路:

首先对每个数据库版本的迁移提供一个依次递增的版本号,这个标识主要是用来检查是否需要做数据库迁移,和要做那些版本的数据迁移,对应上面的问题2。

static const int SDK_DB_VERSION = 2;

在启动 SDK 或者 应用 时,应该判断是否需要做数据库迁移,举个简单的例子:

#define SDK_KEY_DBMIGRATE_DONE(version) [NSString stringWithFormat:@"v_%d_%@", version, @"DBMigrateDone"]

+ (BOOL)needMigrate {
  // 是否已经是最新版本(不需要迁移数据库),是的话直接返回 NO
  BOOL isMigrated = [[NSUserDefaults standardUserDefaults] boolForKey:SDK_KEY_DBMIGRATE_DONE(SDK_DB_VERSION)];
  if (isMigrated) {
     return NO;
  }
  
  BOOL needMigrate = NO;
  // 这里根据你实际的需要做判断
  
  if (!needMigrate) {
     // 更新该版本为已经执行完成数据库升级版本,在每个版本升级完成时,应该把该版本标记为已经执行完成
     [[NSUserDefaults standardUserDefaults] setBool:YES forKey:SDK_KEY_DBMIGRATE_DONE(SDK_DB_VERSION)];
     [[NSUserDefaults standardUserDefaults] synchronize];
  }
  return needMigrate;
}

这里的代码都是简单的举例,根据自己的实际需求写就可以了。

在 SDK 启动的方法前实现数据库迁移功能:

if ([DBMigrateHelper needMigrate]) {
    // 对外抛出开始数据库迁移的 delegate 或者 通知 
    [Delegates onDBMigrateStart];
    
     BOOL isSuccess = [DBMigrateHelper migrateDBToV1HasTried:NO];
      if (!isSuccess) {
        // 失败时重试一次
        isSuccess = [DBMigrateHelper migrateDBToV1HasTried:YES];
      }
      
      // migration to V1 done, failed
      if (!isSuccess) {
          [Delegates onDBMigrateError];
        return;
      }
      
      // V2
      // V3
      // ...
      // 其它版本的数据库迁移操作

     [Delegates onDBMigrateFinish];
    
     // 继续走正常流程
  }

这里需要注意的是在执行各个版本的升级操作前,需要判断下当前版本是否比要升级操作的版本高,如果比升级操作的版本高,说明当前版本不需要这个升级,直接跳到下个版本的升级:

if (database.userVersion >= newVersion) { 
    return;
}

在这里只说大概思路,不涉及数据库操作,数据库操作根据实际去写就可以了。

最后,对 SDK 开发感觉兴趣的朋友可以关注下 我 或者 SDK 开发专题 ,同时欢迎大家投稿。

------------------华丽的分割线------------------

增加两个在实际使用上的建议:

  • 根据版本,单独封装每一版数据库的改变成为对象,这样更方便管理
  • 迁移失败时,提供降级方案,比如使用 Transaction 来进行升级,失败时可以回滚
关注公众号

你可能感兴趣的:(iOS SDK 开发 -- 数据库版本迁移方案)