当前位置:  开发笔记 > 编程语言 > 正文

Sqlite的应用程序内数据库迁移的最佳实践

如何解决《Sqlite的应用程序内数据库迁移的最佳实践》经验,为你挑选了3个好方法。

我正在为我的iphone使用sqlite,我预计数据库架构可能会随着时间而改变.每次成功迁移时需要注意的问题,命名约定和注意事项是什么?

例如,我曾想过将一个版本附加到数据库名称(例如Database_v1).



1> Rngbus..:

我维护一个应用程序,它定期需要更新sqlite数据库并将旧数据库迁移到新模式,这就是我的工作:

为了跟踪数据库版本,我使用sqlite提供的内置用户版本变量(sqlite对此变量不执行任何操作,您可以随意使用它).它从0开始,您可以使用以下sqlite语句获取/设置此变量:

> PRAGMA user_version;  
> PRAGMA user_version = 1;

当应用程序启动时,我会检查当前的用户版本,应用使架构更新所需的任何更改,然后更新用户版本.我将更新包装在事务中,以便在出现任何错误时,不会提交更改.

为了进行模式更改,sqlite支持某些操作的"ALTER TABLE"语法(重命名表或添加列).这是一种就地更新现有表的简便方法.请参阅此处的文档:http://www.sqlite.org/lang_altertable.html.为了删除"ALTER TABLE"语法不支持的列或其他更改,我创建了一个新表,将日期迁移到其中,删除旧表,并将新表重命名为原始名称.


pragma设置不支持参数,您必须提供实际值:"pragma user_version = 1".
通过几个步骤更新数据库,应用从版本1到版本2,然后从版本2到版本3等所需的更改,直到它是最新的.一种简单的方法是使用switch语句,其中每个"case"语句用一个版本更新数据库.您"切换"到当前数据库版本,case语句将一直持续到更新完成.每当更新数据库时,只需添加一个新的case语句.有关此的详细示例,请参阅Billy Gray的以下答案.
我试图有相同的逻辑,但出于某种原因我执行"pragma user_version =?" 以编程方式,它失败了...任何想法?
我有一个问题。假设您的初始版本为1,当前版本为5。版本2、3、4中有一些更新。最终用户仅下载了您的版本1,现在升级到版本5。您应该怎么做?

2> Billy Gray..:

Just Curious的答案是死的(你明白我的意思!),这就是我们用来跟踪应用程序中当前数据库架构的版本.

要运行需要发生的迁移以使user_version与应用程序的预期模式版本匹配,我们使用switch语句.以下是我们的应用条带中的外观示例:

- (void) migrateToSchemaFromVersion:(NSInteger)fromVersion toVersion:(NSInteger)toVersion { 
    // allow migrations to fall thru switch cases to do a complete run
    // start with current version + 1
    [self beginTransaction];
    switch (fromVersion + 1) {
        case 3:
            // change pin type to mode 'pin' for keyboard handling changes
            // removing types from previous schema
            sqlite3_exec(db, "DELETE FROM types;", NULL, NULL, NULL);
            NSLog(@"installing current types");
            [self loadInitialData];
        case 4:
            //adds support for recent view tracking
            sqlite3_exec(db, "ALTER TABLE entries ADD COLUMN touched_at TEXT;", NULL, NULL, NULL);
        case 5:
            {
                sqlite3_exec(db, "ALTER TABLE categories ADD COLUMN image TEXT;", NULL, NULL, NULL);
                sqlite3_exec(db, "ALTER TABLE categories ADD COLUMN entry_count INTEGER;", NULL, NULL, NULL);
                sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS categories_id_idx ON categories(id);", NULL, NULL, NULL);
                sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS categories_name_id ON categories(name);", NULL, NULL, NULL);
                sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS entries_id_idx ON entries(id);", NULL, NULL, NULL);

               // etc...
            }
    }

    [self setSchemaVersion];
    [self endTransaction];
}



3> Andrey Taran..:

让我与FMDB和MBProgressHUD共享一些迁移代码.

这是你如何读取和编写模式版本号(这可能是模型类的一部分,在我的例子中,它是一个名为Database的单例类):

- (int)databaseSchemaVersion {
    FMResultSet *resultSet = [[self database] executeQuery:@"PRAGMA user_version"];
    int version = 0;
    if ([resultSet next]) {
        version = [resultSet intForColumnIndex:0];
    }
    return version;
}

- (void)setDatabaseSchemaVersion:(int)version {
    // FMDB cannot execute this query because FMDB tries to use prepared statements
    sqlite3_exec([self database].sqliteHandle, [[NSString stringWithFormat:@"PRAGMA user_version = %d", DatabaseSchemaVersionLatest] UTF8String], NULL, NULL, NULL);
}

[self database]是懒惰地打开数据库的方法:

- (FMDatabase *)database {
    if (!_databaseOpen) {
        _databaseOpen = YES;

        NSString *documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        NSString *databaseName = [NSString stringWithFormat:@"userdata.sqlite"];

        _database = [[FMDatabase alloc] initWithPath:[documentsDir stringByAppendingPathComponent:databaseName]];
        _database.logsErrors = YES;

        if (![_database openWithFlags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FILEPROTECTION_COMPLETE]) {
            _database = nil;
        } else {
            NSLog(@"Database schema version is %d", [self databaseSchemaVersion]);
        }
    }
    return _database;
}

以下是从视图控制器调用的迁移方法:

- (BOOL)databaseNeedsMigration {
    return [self databaseSchemaVersion] < databaseSchemaVersionLatest;
}

- (void)migrateDatabase {
    int version = [self databaseSchemaVersion];
    if (version >= databaseSchemaVersionLatest)
        return;

    NSLog(@"Migrating database schema from version %d to version %d", version, databaseSchemaVersionLatest);

    // ...the actual migration code...
    if (version < 1) {
        [[self database] executeUpdate:@"CREATE TABLE foo (...)"];
    }

    [self setDatabaseSchemaVersion:DatabaseSchemaVersionLatest];
    NSLog(@"Database schema version after migration is %d", [self databaseSchemaVersion]);
}

这是调用迁移的根视图控制器代码,使用MBProgressHUD显示进度边框:

- (void)viewDidAppear {
    [super viewDidAppear];
    if ([[Database sharedDatabase] userDatabaseNeedsMigration]) {
        MBProgressHUD *hud = [[MBProgressHUD alloc] initWithView:self.view.window];
        [self.view.window addSubview:hud];
        hud.removeFromSuperViewOnHide = YES;
        hud.graceTime = 0.2;
        hud.minShowTime = 0.5;
        hud.labelText = @"Upgrading data";
        hud.taskInProgress = YES;
        [[UIApplication sharedApplication] beginIgnoringInteractionEvents];

        [hud showAnimated:YES whileExecutingBlock:^{
            [[Database sharedDatabase] migrateUserDatabase];
        } onQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0) completionBlock:^{
            [[UIApplication sharedApplication] endIgnoringInteractionEvents];
        }];
    }
}

推荐阅读
kikokikolove
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有