发布网友 发布时间:2022-04-26 06:53
共4个回答
懂视网 时间:2022-05-05 06:23
本文主要介绍了IOS 数据库升级数据迁移的实例详解的相关资料,这里提供实例帮助大家解决数据库升级及数据迁移的问题,需要的朋友可以参考下,希望能帮助到大家。IOS 数据库升级数据迁移的实例详解
概要:
很久以前就遇到过数据库版本升级的引用场景,当时的做法是简单的删除旧的数据库文件,重建数据库和表结构,这种暴力升级的方式会导致旧的数据的丢失,现在看来这并不不是一个优雅的解决方案,现在一个新的项目中又使用到了数据库,我不得不重新考虑这个问题,我希望用一种比较优雅的方式去解决这个问题,以后我们还会遇到类似的场景,我们都想做的更好不是吗?
理想的情况是:数据库升级,表结构、主键和约束有变化,新的表结构建立之后会自动的从旧的表检索数据,相同的字段进行映射迁移数据,而绝大多数的业务场景下的数据库版本升级是只涉及到字段的增减、修改主键约束,所以下面要实现的方案也是从最基本的、最常用的业务场景去做一个实现,至于更加复杂的场景,可以在此基础上进行扩展,达到符合自己的预期的。
选型定型
网上搜索了下,并没有数据库升级数据迁移简单完整的解决方案,找到了一些思路
1.清除旧的数据,重建表
优点:简单
缺点:数据丢失
2.在已有表的基础上对表结构进行修改
优点:能够保留数据
缺点:规则比较繁琐,要建立一个数据库的字段配置文件,然后读取配置文件,执行SQL修改表结构、约束和主键等等,涉及到跨多个版本的数据库升级就变得繁琐并且麻烦了
3.创建临时表,把旧的数据拷贝到临时表,然后删除旧的数据表并且把临时表设置为数据表。
优点:能够保留数据,支持表结构的修改,约束、主键的变更,实现起来比较简单
缺点:实现的步骤比较多
综合考虑,第三种方法是一个比较靠谱的方案。
主要步骤
根据这个思路,分析了一下数据库升级了主要步骤大概如下:
获取数据库中旧的表
修改表名,添加后缀“_bak”,把旧的表当做备份表
创建新的表
获取新创建的表
遍历旧的表和新表,对比取出需要迁移的表的字段
数据迁移处理
删除备份表
使用到的SQL语句分析
这些操作都是和数据库操作有关系的,所以问题的关键是对应步骤的SQL语句了,下面分析下用到的主要的SQL语句:
获取数据库中旧的表
SELECT * from sqlite_master WHERE type='table'
结果如下,可以看到有type | name | tbl_name | rootpage | sql 这些数据库字段,我们只要用到name也就是数据库名称这个字段就行了
sqlite> SELECT * from sqlite_master WHERE type='table' ...> ; +-------+---------------+---------------+----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | type | name | tbl_name | rootpage | sql | +-------+---------------+---------------+----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | table | t_message_bak | t_message_bak | 2 | CREATE TABLE "t_message_bak" (messageID TEXT, messageType INTEGER, messageJsonContent TEXT, retriveTimeString INTEGER, postTimeString INTEGER, readState INTEGER, PRIMARY KEY(messageID)) | | table | t_message | t_message | 4 | CREATE TABLE t_message ( messageID TEXT, messageType INTEGER, messageJsonContent TEXT, retriveTimeString INTEGER, postTimeString INTEGER, readState INTEGER, addColumn INTEGER, PRIMARY KEY(messageID) ) | +-------+---------------+---------------+----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 2 行于数据集 (0.03 秒)
修改表名,添加后缀“_bak”,把旧的表当做备份表
-- 把t_message表修改为t_message_bak表 ALTER TABLE t_message RENAME TO t_message_bak
获取表字段信息
-- 获取t_message_bak表的字段信息 PRAGMA table_info('t_message_bak')
获取到的表字段信息如下,可以看到有| cid | name | type | notnull | dflt_value | pk | 这些数据库字段,我们只要用到name也就是字段名称这个字段就行了
sqlite> PRAGMA table_info('t_message_bak'); +------+--------------------+---------+---------+------------+------+ | cid | name | type | notnull | dflt_value | pk | +------+--------------------+---------+---------+------------+------+ | 0 | messageID | TEXT | 0 | NULL | 1 | | 1 | messageType | INTEGER | 0 | NULL | 0 | | 2 | messageJsonContent | TEXT | 0 | NULL | 0 | | 3 | retriveTimeString | INTEGER | 0 | NULL | 0 | | 4 | postTimeString | INTEGER | 0 | NULL | 0 | | 5 | readState | INTEGER | 0 | NULL | 0 | +------+--------------------+---------+---------+------------+------+ 6 行于数据集 (0.01 秒)
使用子查询进行数据迁移处理
INSERT INTO t_message(messageID, messageType, messageJsonContent, retriveTimeString, postTimeString, readState) SELECT messageID, messageType, messageJsonContent, retriveTimeString, postTimeString, readState FROM t_message_bak
把t_message_bak表中的messageID, messageType, messageJsonContent, retriveTimeString, postTimeString, readState这些字段的值复制到t_message表中
代码实现
接下来就到了代码的实现步骤了
// 创建新的临时表,把数据导入临时表,然后用临时表替换原表 - (void)baseDBVersionControl { NSString * version_old = ValueOrEmpty(MMUserDefault.dbVersion); NSString * version_new = [NSString stringWithFormat:@"%@", DB_Version]; NSLog(@"dbVersionControl before: %@ after: %@",version_old,version_new); // 数据库版本升级 if (version_old != nil && ![version_new isEqualToString:version_old]) { // 获取数据库中旧的表 NSArray* existsTables = [self sqliteExistsTables]; NSMutableArray* tmpExistsTables = [NSMutableArray array]; // 修改表名,添加后缀“_bak”,把旧的表当做备份表 for (NSString* tablename in existsTables) { [tmpExistsTables addObject:[NSString stringWithFormat:@"%@_bak", tablename]]; [self.databaseQueue inDatabase:^(FMDatabase *db) { NSString* sql = [NSString stringWithFormat:@"ALTER TABLE %@ RENAME TO %@_bak", tablename, tablename]; [db executeUpdate:sql]; }]; } existsTables = tmpExistsTables; // 创建新的表 [self initTables]; // 获取新创建的表 NSArray* newAddedTables = [self sqliteNewAddedTables]; // 遍历旧的表和新表,对比取出需要迁移的表的字段 NSDictionary* migrationInfos = [self generateMigrationInfosWithOldTables:existsTables newTables:newAddedTables]; // 数据迁移处理 [migrationInfos enumerateKeysAndObjectsUsingBlock:^(NSString* newTableName, NSArray* publicColumns, BOOL * _Nonnull stop) { NSMutableString* colunmsString = [NSMutableString new]; for (int i = 0; i<publicColumns.count; i++) { [colunmsString appendString:publicColumns[i]]; if (i != publicColumns.count-1) { [colunmsString appendString:@", "]; } } NSMutableString* sql = [NSMutableString new]; [sql appendString:@"INSERT INTO "]; [sql appendString:newTableName]; [sql appendString:@"("]; [sql appendString:colunmsString]; [sql appendString:@")"]; [sql appendString:@" SELECT "]; [sql appendString:colunmsString]; [sql appendString:@" FROM "]; [sql appendFormat:@"%@_bak", newTableName]; [self.databaseQueue inDatabase:^(FMDatabase *db) { [db executeUpdate:sql]; }]; }]; // 删除备份表 [self.databaseQueue inDatabase:^(FMDatabase *db) { [db beginTransaction]; for (NSString* oldTableName in existsTables) { NSString* sql = [NSString stringWithFormat:@"DROP TABLE IF EXISTS %@", oldTableName]; [db executeUpdate:sql]; } [db commit]; }]; MMUserDefault.dbVersion = version_new; } else { MMUserDefault.dbVersion = version_new; } } - (NSDictionary*)generateMigrationInfosWithOldTables:(NSArray*)oldTables newTables:(NSArray*)newTables { NSMutableDictionary<NSString*, NSArray* >* migrationInfos = [NSMutableDictionary dictionary]; for (NSString* newTableName in newTables) { NSString* oldTableName = [NSString stringWithFormat:@"%@_bak", newTableName]; if ([oldTables containsObject:oldTableName]) { // 获取表数据库字段信息 NSArray* oldTableColumns = [self sqliteTableColumnsWithTableName:oldTableName]; NSArray* newTableColumns = [self sqliteTableColumnsWithTableName:newTableName]; NSArray* publicColumns = [self publicColumnsWithOldTableColumns:oldTableColumns newTableColumns:newTableColumns]; if (publicColumns.count > 0) { [migrationInfos setObject:publicColumns forKey:newTableName]; } } } return migrationInfos; } - (NSArray*)publicColumnsWithOldTableColumns:(NSArray*)oldTableColumns newTableColumns:(NSArray*)newTableColumns { NSMutableArray* publicColumns = [NSMutableArray array]; for (NSString* oldTableColumn in oldTableColumns) { if ([newTableColumns containsObject:oldTableColumn]) { [publicColumns addObject:oldTableColumn]; } } return publicColumns; } - (NSArray*)sqliteTableColumnsWithTableName:(NSString*)tableName { __block NSMutableArray<NSString*>* tableColumes = [NSMutableArray array]; [self.databaseQueue inDatabase:^(FMDatabase *db) { NSString* sql = [NSString stringWithFormat:@"PRAGMA table_info('%@')", tableName]; FMResultSet *rs = [db executeQuery:sql]; while ([rs next]) { NSString* columnName = [rs stringForColumn:@"name"]; [tableColumes addObject:columnName]; } }]; return tableColumes; } - (NSArray*)sqliteExistsTables { __block NSMutableArray<NSString*>* existsTables = [NSMutableArray array]; [self.databaseQueue inDatabase:^(FMDatabase *db) { NSString* sql = @"SELECT * from sqlite_master WHERE type='table'"; FMResultSet *rs = [db executeQuery:sql]; while ([rs next]) { NSString* tablename = [rs stringForColumn:@"name"]; [existsTables addObject:tablename]; } }]; return existsTables; } - (NSArray*)sqliteNewAddedTables { __block NSMutableArray<NSString*>* newAddedTables = [NSMutableArray array]; [self.databaseQueue inDatabase:^(FMDatabase *db) { NSString* sql = @"SELECT * from sqlite_master WHERE type='table' AND name NOT LIKE '%_bak'"; FMResultSet *rs = [db executeQuery:sql]; while ([rs next]) { NSString* tablename = [rs stringForColumn:@"name"]; [newAddedTables addObject:tablename]; } }]; return newAddedTables; }
热心网友 时间:2022-05-05 03:31
用iTunes转移个人数据到新iPhone
如何转移个人数据到新iPhone
当更换iPhone手机时最需要做的事就是,如何快速的把旧iPhone个人数据转移到新iPhone上。通过iTunes软件的备份和恢复功能可以实现,通过同步助手的备份恢复功能也能实现。本经验将分别介绍利用上述两种工具软件来转移个人数据的方法。
打开iTunes后通过文件下拉菜单找到“设备-备份”命令,单击后iTunes即会实施关于iPhone通讯录、备忘录等个人数据的备份工具。备份完成后再连接新的iPhone设备,在该菜单栏下再单击“从备份恢复”一项来转移到新iPhone即可。
新买的iphone6s已经陆续到货了,如何把旧的苹果手机中的数据转移到新手机中呢?旧苹果手机数据怎么传到新iphone6s?下面为大家带来ios数据迁移教程。
旧苹果手机数据怎么传到新iphone6s ios数据迁移教程 第 0 步:理论上来说,最好将老款设备也升级到 iOS 9
有一件事要先说明,哪怕你的 iPhone 6s 还没有到手,你也可以按本文中提供的方法,做好提前准备工作,这样你收到新款 iPhone 后就可以更加快速地完成数据迁移了。当然,由于 iPhone 6s 默认预装 iOS 9 系统,所以为了保持数据的一致性,建议在开始之前,也将老款设备升级到 iOS 9。
第 1 步:放弃 iCloud,用 iTunes 来二次备份你的 iPhone
iPhone 目前支持两种备份模式:iTunes 或 iCloud。没错,iCloud 的确很方便,每次晚上睡觉的时候,iPhone 都会在充电时自动通过无线网络完成增量更新,而且只要有 WiFi 网络连接,你可以在任何地方随时通过 iCloud 恢复备份。不过,iCloud 在初始化备份和完全还原时,最大的劣势就是:慢。特别是如果数据量较大,这个过程简直就是煎熬。因此,即使你是一个 iCloud 付费用户,除非你手头暂时没有电脑,否则都不要用 iCloud 在新老设备之间迁移数据。
在不同 iPhone 之间迁移数据最快速的办法,就是在电脑上打开 iTunes,在左上角的一排图标中点击 iPhone 图标(如图所示)。在左侧边栏中,你会看到包含摘要、应用、音乐、影片等设置选项,这时候默认应该就在「摘要」标签页上。
在「备份」项目中,你会看到自动备份有两个选项:iCloud 或本电脑。没错,选择「本电脑」,并勾上「给 iPhone 备份加密」。不要小看这一步,可以节省你很多时间和麻烦:当从加密的备份中恢复数据时,你不需要在还原的过程中一遍又一遍地输入密码。
好了,现在可以按下「立即备份」那个按钮了。这时可能会有一个弹窗,问你是否要传输所有购买项目,如果有的话,选择「传输购买项目」就可以。接下来,备份的过程可能会占用数分钟到一小时不等。一旦备份完成,「最新的备份」会显示当前的日期。好了,现在再来左手右遍一个慢动作重复一次刚才的操作,再备份一次。这样的二次备份可以确保所有数据万无一失地都被备份到了电脑上,不用担心有任何遗失。
第 2 步:不用了的话,将老设备彻底清空吧
按之前的第 1 步操作备份后,在新手机到手前还可以继续用一段时间,或者你也可以将它彻底清空转手出售。
如果继续使用的话,请确保在将数据迁移到新手机之前,一定要再对老设备重复一次刚才的 iTunes 备份操作。一般来说,我都会重复刚才那样的二次备份,由于是增量备份,第二次备份所花费的时间很少。
如果你打算彻底清空老款 iPhone,最简单的方式就是进入「设置 - 通用 - 还原 - 抹掉所有内容和设备」。在执行这个操作时,会要求你关闭验证锁,一旦关闭后,iPhone 将和你的 iCloud 账号解绑,从而也无法再次使用诸如「找回我的 iPhone」这样的定位功能。至此,老设备就可以上微博吆喝两嗓子转手了。
第 3 步:用 iTunes 将备份还原到 iPhone 6s 上
这也是最简单的一步。当 iPhone 6s 到手时,你都不会在屏幕上做任何操作,只需要用数据库将它连上电脑,打开 iTunes,这时就会跳出欢迎使用新 iPhone 的页面。你只需要选择「从此备份中恢复」,iTunes 会搞定剩下的一切。所有的个人数据和设备选项都会被恢复到新手机上,这时 iTunes 会重启你的手机,并开始逐个恢复 app 和媒体文件的数据。整个过程肯定比用 iCloud 还原相同的数据量,要快得多。
并且如果你按照之前我们所说的,使用的是加密的备份方式,基本上整个过程不需要你手动做什么干预。只有在第一次重启时,可能需要你输入 iCloud 或者 iTunes 的备份密码,以确保你授权新设备接收所有之前备份的内容。当然,和 Touch ID 以及 Apple Pay 有关的设置,你需要在新的 iPhone 6s 上重新单独设置,因为隐私保护的原因,这些数据只会存储在单一设备下,不能在多设备间迁移或同步。
热心网友 时间:2022-05-05 05:06
在电脑安装itools,为了确保数据安全,建议在其官方网站下载。先将旧的苹果手机连接电脑,建议使用苹果手机的原装数据线。连接手机后运行itools,等待识别手机并安装驱动,出现手机型号就表示连接成功。在我的设备下方,是可管理项目列表。首先点击照片。右侧显示出手机相册下相薄,照片分相薄存放。选择全部,点击导出,可以将手机所有照片复制到电脑。
热心网友 时间:2022-05-05 06:57
苹果手机你是可以通过U盘把数据转移的,但是苹果的数据转移是比较麻烦的