0

0

实例详解IOS 数据库升级数据迁移

小云云

小云云

发布时间:2017-12-25 14:09:07

|

2014人浏览过

|

来源于php中文网

原创

本文主要介绍了ios 数据库升级数据迁移的实例详解的相关资料,这里提供实例帮助大家解决数据库升级及数据迁移的问题,需要的朋友可以参考下,希望能帮助到大家。

IOS 数据库升级数据迁移的实例详解

概要:

很久以前就遇到过数据库版本升级的引用场景,当时的做法是简单的删除旧的数据库文件,重建数据库和表结构,这种暴力升级的方式会导致旧的数据的丢失,现在看来这并不不是一个优雅的解决方案,现在一个新的项目中又使用到了数据库,我不得不重新考虑这个问题,我希望用一种比较优雅的方式去解决这个问题,以后我们还会遇到类似的场景,我们都想做的更好不是吗?

理想的情况是:数据库升级,表结构、主键和约束有变化,新的表结构建立之后会自动的从旧的表检索数据,相同的字段进行映射迁移数据,而绝大多数的业务场景下的数据库版本升级是只涉及到字段的增减、修改主键约束,所以下面要实现的方案也是从最基本的、最常用的业务场景去做一个实现,至于更加复杂的场景,可以在此基础上进行扩展,达到符合自己的预期的。

选型定型

网上搜索了下,并没有数据库升级数据迁移简单完整的解决方案,找到了一些思路

1.清除旧的数据,重建表

优点:简单
缺点:数据丢失

2.在已有表的基础上对表结构进行修改

优点:能够保留数据
缺点:规则比较繁琐,要建立一个数据库的字段配置文件,然后读取配置文件,执行SQL修改表结构、约束和主键等等,涉及到跨多个版本的数据库升级就变得繁琐并且麻烦了

3.创建临时表,把旧的数据拷贝到临时表,然后删除旧的数据表并且把临时表设置为数据表。

优点:能够保留数据,支持表结构的修改,约束、主键的变更,实现起来比较简单
缺点:实现的步骤比较多

综合考虑,第三种方法是一个比较靠谱的方案。

主要步骤

根据这个思路,分析了一下数据库升级了主要步骤大概如下:

  • 获取数据库中旧的表

  • 修改表名,添加后缀“_bak”,把旧的表当做备份表

  • 创建新的表

  • 获取新创建的表

    PHP高级开发技巧与范例
    PHP高级开发技巧与范例

    PHP是一种功能强大的网络程序设计语言,而且易学易用,移植性和可扩展性也都非常优秀,本书将为读者详细介绍PHP编程。 全书分为预备篇、开始篇和加速篇三大部分,共9章。预备篇主要介绍一些学习PHP语言的预备知识以及PHP运行平台的架设;开始篇则较为详细地向读者介绍PKP语言的基本语法和常用函数,以及用PHP如何对MySQL数据库进行操作;加速篇则通过对典型实例的介绍来使读者全面掌握PHP。 本书

    下载
  • 遍历旧的表和新表,对比取出需要迁移的表的字段

  • 数据迁移处理

  • 删除备份表

使用到的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* 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* 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* 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* 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;
}

相关推荐:

sql 2005 数据库升级2008 数据库 和2005 数据附加2008数据备份文

SQL server 数据库升级版本问题解决办法

详解oracle数据库迁移到MySQL的方法总结(图文)

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

54

2026.01.31

高干文在线阅读网站大全
高干文在线阅读网站大全

汇集热门1v1高干文免费阅读资源,涵盖都市言情、京味大院、军旅高干等经典题材,情节紧凑、人物鲜明。阅读专题下面的文章了解更多详细内容。

40

2026.01.31

无需付费的漫画app大全
无需付费的漫画app大全

想找真正免费又无套路的漫画App?本合集精选多款永久免费、资源丰富、无广告干扰的优质漫画应用,涵盖国漫、日漫、韩漫及经典老番,满足各类阅读需求。阅读专题下面的文章了解更多详细内容。

50

2026.01.31

漫画免费在线观看地址大全
漫画免费在线观看地址大全

想找免费又资源丰富的漫画网站?本合集精选2025-2026年热门平台,涵盖国漫、日漫、韩漫等多类型作品,支持高清流畅阅读与离线缓存。阅读专题下面的文章了解更多详细内容。

12

2026.01.31

漫画防走失登陆入口大全
漫画防走失登陆入口大全

2026最新漫画防走失登录入口合集,汇总多个稳定可用网址,助你畅享高清无广告漫画阅读体验。阅读专题下面的文章了解更多详细内容。

13

2026.01.31

php多线程怎么实现
php多线程怎么实现

PHP本身不支持原生多线程,但可通过扩展如pthreads、Swoole或结合多进程、协程等方式实现并发处理。阅读专题下面的文章了解更多详细内容。

1

2026.01.31

php如何运行环境
php如何运行环境

本合集详细介绍PHP运行环境的搭建与配置方法,涵盖Windows、Linux及Mac系统下的安装步骤、常见问题及解决方案。阅读专题下面的文章了解更多详细内容。

0

2026.01.31

php环境变量如何设置
php环境变量如何设置

本合集详细讲解PHP环境变量的设置方法,涵盖Windows、Linux及常见服务器环境配置技巧,助你快速掌握环境变量的正确配置。阅读专题下面的文章了解更多详细内容。

0

2026.01.31

php图片如何上传
php图片如何上传

本合集涵盖PHP图片上传的核心方法、安全处理及常见问题解决方案,适合初学者与进阶开发者。阅读专题下面的文章了解更多详细内容。

2

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 8.2万人学习

Django 教程
Django 教程

共28课时 | 3.7万人学习

Excel 教程
Excel 教程

共162课时 | 14.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号