麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 數(shù)據(jù)庫 > MySQL > 正文

IOS 數(shù)據(jù)庫升級數(shù)據(jù)遷移的實(shí)例詳解

2024-07-24 13:14:07
字體:
供稿:網(wǎng)友

IOS 數(shù)據(jù)庫升級數(shù)據(jù)遷移的實(shí)例詳解

概要:

很久以前就遇到過數(shù)據(jù)庫版本升級的引用場景,當(dāng)時的做法是簡單的刪除舊的數(shù)據(jù)庫文件,重建數(shù)據(jù)庫和表結(jié)構(gòu),這種暴力升級的方式會導(dǎo)致舊的數(shù)據(jù)的丟失,現(xiàn)在看來這并不不是一個優(yōu)雅的解決方案,現(xiàn)在一個新的項(xiàng)目中又使用到了數(shù)據(jù)庫,我不得不重新考慮這個問題,我希望用一種比較優(yōu)雅的方式去解決這個問題,以后我們還會遇到類似的場景,我們都想做的更好不是嗎?

理想的情況是:數(shù)據(jù)庫升級,表結(jié)構(gòu)、主鍵和約束有變化,新的表結(jié)構(gòu)建立之后會自動的從舊的表檢索數(shù)據(jù),相同的字段進(jìn)行映射遷移數(shù)據(jù),而絕大多數(shù)的業(yè)務(wù)場景下的數(shù)據(jù)庫版本升級是只涉及到字段的增減、修改主鍵約束,所以下面要實(shí)現(xiàn)的方案也是從最基本的、最常用的業(yè)務(wù)場景去做一個實(shí)現(xiàn),至于更加復(fù)雜的場景,可以在此基礎(chǔ)上進(jìn)行擴(kuò)展,達(dá)到符合自己的預(yù)期的。

選型定型

網(wǎng)上搜索了下,并沒有數(shù)據(jù)庫升級數(shù)據(jù)遷移簡單完整的解決方案,找到了一些思路

1.清除舊的數(shù)據(jù),重建表

優(yōu)點(diǎn):簡單
缺點(diǎn):數(shù)據(jù)丟失

2.在已有表的基礎(chǔ)上對表結(jié)構(gòu)進(jìn)行修改

優(yōu)點(diǎn):能夠保留數(shù)據(jù)
缺點(diǎn):規(guī)則比較繁瑣,要建立一個數(shù)據(jù)庫的字段配置文件,然后讀取配置文件,執(zhí)行SQL修改表結(jié)構(gòu)、約束和主鍵等等,涉及到跨多個版本的數(shù)據(jù)庫升級就變得繁瑣并且麻煩了

3.創(chuàng)建臨時表,把舊的數(shù)據(jù)拷貝到臨時表,然后刪除舊的數(shù)據(jù)表并且把臨時表設(shè)置為數(shù)據(jù)表。

優(yōu)點(diǎn):能夠保留數(shù)據(jù),支持表結(jié)構(gòu)的修改,約束、主鍵的變更,實(shí)現(xiàn)起來比較簡單
缺點(diǎn):實(shí)現(xiàn)的步驟比較多

綜合考慮,第三種方法是一個比較靠譜的方案。

主要步驟

根據(jù)這個思路,分析了一下數(shù)據(jù)庫升級了主要步驟大概如下:

  • 獲取數(shù)據(jù)庫中舊的表
  • 修改表名,添加后綴“_bak”,把舊的表當(dāng)做備份表
  • 創(chuàng)建新的表
  • 獲取新創(chuàng)建的表
  • 遍歷舊的表和新表,對比取出需要遷移的表的字段
  • 數(shù)據(jù)遷移處理
  • 刪除備份表

使用到的SQL語句分析

這些操作都是和數(shù)據(jù)庫操作有關(guān)系的,所以問題的關(guān)鍵是對應(yīng)步驟的SQL語句了,下面分析下用到的主要的SQL語句:

獲取數(shù)據(jù)庫中舊的表

SELECT * from sqlite_master WHERE type='table'

結(jié)果如下,可以看到有type | name | tbl_name | rootpage | sql 這些數(shù)據(jù)庫字段,我們只要用到name也就是數(shù)據(jù)庫名稱這個字段就行了

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 行于數(shù)據(jù)集 (0.03 秒)

修改表名,添加后綴“_bak”,把舊的表當(dāng)做備份表

-- 把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 | 這些數(shù)據(jù)庫字段,我們只要用到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 行于數(shù)據(jù)集 (0.01 秒)

使用子查詢進(jìn)行數(shù)據(jù)遷移處理

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這些字段的值復(fù)制到t_message表中

代碼實(shí)現(xiàn)

接下來就到了代碼的實(shí)現(xiàn)步驟了

// 創(chuàng)建新的臨時表,把數(shù)據(jù)導(dǎo)入臨時表,然后用臨時表替換原表- (void)baseDBVersionControl { NSString * version_old = ValueOrEmpty(MMUserDefault.dbVersion); NSString * version_new = [NSString stringWithFormat:@"%@", DB_Version]; NSLog(@"dbVersionControl before: %@ after: %@",version_old,version_new); // 數(shù)據(jù)庫版本升級 if (version_old != nil && ![version_new isEqualToString:version_old]) {  // 獲取數(shù)據(jù)庫中舊的表  NSArray* existsTables = [self sqliteExistsTables];  NSMutableArray* tmpExistsTables = [NSMutableArray array];  // 修改表名,添加后綴“_bak”,把舊的表當(dāng)做備份表  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;  // 創(chuàng)建新的表  [self initTables];  // 獲取新創(chuàng)建的表  NSArray* newAddedTables = [self sqliteNewAddedTables];  // 遍歷舊的表和新表,對比取出需要遷移的表的字段  NSDictionary* migrationInfos = [self generateMigrationInfosWithOldTables:existsTables newTables:newAddedTables];  // 數(shù)據(jù)遷移處理  [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]) {   // 獲取表數(shù)據(jù)庫字段信息   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;}

問題

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

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


注:相關(guān)教程知識閱讀請移步到MYSQL教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 色中色激情影院 | 91av在线影院 | www.xxx视频| 麻豆porn| 日本黄色一级视频 | 高潮娇喘嗯啊~文字 | 国产一级一级 | 99激情视频| 热99精品视频 | 亚洲一区在线国产 | 日本一级黄色大片 | 免费a级网站 | 精品一区二区免费视频视频 | 黄色免费在线电影 | sese综合| 91短视频在线 | 精品久久久久久久久久久久包黑料 | 蜜桃传媒视频麻豆第一区免费观看 | av电影在线观看网站 | 成人福利视频网站 | 毛片在哪里看 | 色网站在线免费观看 | 精品一区二区6 | 精品亚洲一区二区三区 | 毛片网站网址 | 欧美视频在线观看一区 | 欧美成网 | 欧洲精品久久 | 国内毛片视频 | 嫩呦国产一区二区三区av | 91短视频版高清在线观看免费 | 国产成人视屏 | 毛片118极品美女写真 | 国产精品色综合 | 亚洲国产精品一区二区久久 | av免费入口 | 国产va在线观看 | 日产精品久久久一区二区开放时间 | 制服丝袜日日夜夜 | 最新中文字幕日本 | 久久久久久久久浪潮精品 |