實例詳解IOS 資料庫升級資料遷移

小云云
發布: 2017-12-25 14:09:07
原創
1954 人瀏覽過

本文主要介紹了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* 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的方法總結(圖文)

以上是實例詳解IOS 資料庫升級資料遷移的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!