婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > IOS 數據庫升級數據遷移的實例詳解

IOS 數據庫升級數據遷移的實例詳解

熱門標簽:寧波企業外呼系統收費 上海智能外呼系統代理商 成都優派外呼系統 地圖標注人員兼職 扎樣申請400電話 ps制作地圖標注gif 電子地圖標注電話 聊城智能外呼系統運營商 沈陽電銷外呼系統原理是什么

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; ipublicColumns.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 {
 NSMutableDictionaryNSString*, 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 NSMutableArrayNSString*>* 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 NSMutableArrayNSString*>* 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 NSMutableArrayNSString*>* 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;
}

問題

sqlite 刪除表文件的大小不變的問題

如有疑問請留言或者到本站社區交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

您可能感興趣的文章:
  • VUE中使用HTTP庫Axios方法詳解
  • iOS系統的底層通知框架庫示例詳解
  • 淺談強大易用支持URL Rewrite的iOS路由庫FFRouter
  • iOS開發筆記之鍵盤、靜態庫、動畫和Crash定位
  • 基于iOS Realm數據庫的使用實例詳解
  • iOS開發中如何優雅的調試數據庫詳解
  • iOS中.a和.framework靜態庫的創建與.bundle資源包的使用詳解
  • IOS UIImagePickerController從拍照、圖庫、相冊獲取圖片
  • iOS中FMDB數據庫之增刪改查使用實例
  • ios動態庫和靜態庫的區別

標簽:汕頭 宿州 三明 咸寧 內江 林芝 朔州 AXB

巨人網絡通訊聲明:本文標題《IOS 數據庫升級數據遷移的實例詳解》,本文關鍵詞  IOS,數據庫,升級,數據,遷移,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《IOS 數據庫升級數據遷移的實例詳解》相關的同類信息!
  • 本頁收集關于IOS 數據庫升級數據遷移的實例詳解的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    亚洲乱码国产乱码精品精98午夜| 狠狠色丁香婷婷综合久久片| 国产精品蜜臀av| 国产精品88av| 亚洲国产高清在线观看视频| 日韩精彩视频在线观看| 欧美日韩精品系列| 久久尤物电影视频在线观看| 国产欧美一区二区精品性| 美女免费视频一区二区| 日韩欧美一级在线播放| 日本一区中文字幕| 色狠狠一区二区三区香蕉| 国产精品美女一区二区| 欧美日韩国产中文| 欧美大胆人体bbbb| 成人动漫av在线| 欧美人妇做爰xxxⅹ性高电影| 成年人国产精品| gogo大胆日本视频一区| 色94色欧美sute亚洲13| 欧美影院一区二区| 成人黄动漫网站免费app| 琪琪久久久久日韩精品| 欧美亚洲丝袜传媒另类| 五月婷婷综合网| 99精品视频在线免费观看| 日本亚洲免费观看| 日韩中文字幕亚洲一区二区va在线| 首页国产丝袜综合| 久久久久久久久久久久久夜| 欧美精品一区二区三区蜜桃| 欧美人妖巨大在线| 成人h动漫精品一区二区| 国产一区二区三区精品视频| 亚洲综合免费观看高清在线观看| 久久综合五月天婷婷伊人| 99视频精品在线| 91精品国产全国免费观看| 欧美日韩精品一区视频| 欧美丰满高潮xxxx喷水动漫| 欧美刺激午夜性久久久久久久| 正在播放亚洲一区| 亚洲第一搞黄网站| 日韩av网站免费在线| 亚洲国产一二三| 国产亚洲欧洲一区高清在线观看| 国产精品888| 97国产精品videossex| 久久久一区二区三区| 日本中文字幕一区二区视频| 亚洲欧美综合另类在线卡通| 一区二区三区四区在线| 国精产品一区一区三区mba桃花| 国产.欧美.日韩| 日韩午夜中文字幕| 亚洲男人的天堂网| 97久久精品人人澡人人爽| 国产精品一二三| 26uuu欧美| 制服.丝袜.亚洲.中文.综合| 日韩色视频在线观看| 久久久久久久久蜜桃| 亚洲综合丁香婷婷六月香| 蜜臀99久久精品久久久久久软件| 国产suv精品一区二区三区| 欧美久久久久免费| 中文字幕佐山爱一区二区免费| 久久国产精品72免费观看| 91丨porny丨中文| 久久久久久久久久久久久久久99 | 在线观看视频一区| 国产欧美一区二区精品秋霞影院| 亚洲福中文字幕伊人影院| 成人午夜av电影| 精品少妇一区二区三区| 亚洲欧洲制服丝袜| av在线这里只有精品| 精品国产麻豆免费人成网站| 亚洲综合免费观看高清完整版在线| 成人免费视频视频| fc2成人免费人成在线观看播放| 91麻豆免费观看| 欧美高清视频不卡网| 99re视频精品| 精品一区二区国语对白| 日韩电影免费在线看| 蜜桃视频一区二区三区在线观看 | 日韩欧美视频在线| 国产一区美女在线| 亚洲日本欧美天堂| 日韩视频永久免费| av成人老司机| 亚洲男帅同性gay1069| 国产麻豆一精品一av一免费| 中日韩免费视频中文字幕| 免费一级欧美片在线观看| 欧美制服丝袜第一页| 中文字幕在线一区二区三区| 国内精品伊人久久久久av一坑| 2020国产精品自拍| 亚洲成人手机在线| 国产精品久久毛片a| 亚洲欧洲成人av每日更新| 欧美精品少妇一区二区三区| 中文字幕在线观看一区| 成人综合婷婷国产精品久久| 国产不卡在线一区| 欧美日韩精品欧美日韩精品一综合| 亚洲成人av免费| 精品欧美乱码久久久久久1区2区| 91首页免费视频| 91在线播放网址| 欧美va亚洲va香蕉在线| 欧美日韩的一区二区| 亚洲不卡一区二区三区| 欧美日本视频在线| 看片网站欧美日韩| 国产精品日韩成人| 在线一区二区三区| 亚洲sss视频在线视频| 亚洲精品在线一区二区| 成人毛片老司机大片| 亚洲一区在线观看免费观看电影高清 | 五月激情综合色| 538prom精品视频线放| 国产精品一级黄| 一区二区免费看| 欧美一级在线观看| 成人av免费在线| 午夜精品国产更新| 国产精品欧美经典| 91精品国产aⅴ一区二区| 国产成人三级在线观看| 天天免费综合色| 国产精品网友自拍| 日韩午夜在线观看视频| 9人人澡人人爽人人精品| 人人爽香蕉精品| 国产精品久久毛片| 精品美女一区二区| 欧美性感一类影片在线播放| 国产一区二区91| 在线播放欧美女士性生活| 国产精品不卡一区二区三区| 麻豆精品新av中文字幕| 色欧美片视频在线观看| 亚洲国产精品精华液ab| 国产成人aaaa| 自拍偷拍亚洲激情| 91高清视频在线| 亚洲国产中文字幕| 日韩免费福利电影在线观看| 毛片av一区二区| 中文字幕中文字幕一区二区| 成人精品一区二区三区中文字幕| 国产欧美日韩另类视频免费观看| 成人看片黄a免费看在线| 国产农村妇女精品| 久久午夜老司机| 性做久久久久久免费观看欧美| 日本欧洲一区二区| 丁香天五香天堂综合| 午夜av区久久| 91丝袜美腿高跟国产极品老师| 国产精品一区二区黑丝| 日日欢夜夜爽一区| 一区二区在线观看av| 亚洲国产精品黑人久久久| 26uuu另类欧美| 日韩欧美中文字幕精品| 欧美精品精品一区| 欧美片在线播放| 欧美日韩亚洲综合在线| 日本韩国精品在线| 黄色成人免费在线| 黄色精品一二区| 亚洲欧洲色图综合| 精品欧美乱码久久久久久1区2区 | 久久久亚洲精华液精华液精华液 | 91在线精品一区二区| 一区二区三区四区亚洲| 国产亚洲美州欧州综合国| 日韩av不卡一区二区| 日韩一区二区三区视频在线观看 | 日韩视频在线观看一区二区| 麻豆国产欧美一区二区三区| 欧美日本在线视频| 国产日韩精品一区二区浪潮av| 国产资源精品在线观看| 日韩女优电影在线观看| 国产麻豆9l精品三级站| 国产精品乱码久久久久久| 色综合天天综合给合国产| 午夜亚洲福利老司机| 久久综合av免费| 色哟哟国产精品| 精品一区二区三区香蕉蜜桃| 日本一区二区综合亚洲| 欧美日韩一区小说|