#define YstenFriendDBManager_ValueOrEmpty(value) ((value)?(value):@"")sql
// 設置版本號和表中個數 在須要的方法中調用
[self versionControlWithNewDBVersion:DBVersion];
// 設置數據庫版本號和當前表中有多少字段
- (void)setDBVersion:(NSString*)DBVersion andDBCount:(NSString *)DBCount{
[[NSUserDefaults standardUserDefaults] setObject:DBVersion forKey:DB_Version_Key];
[[NSUserDefaults standardUserDefaults] setObject:DBCount forKey:DB_Count_Key];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (NSString*)DBVersion {
return [[NSUserDefaults standardUserDefaults] objectForKey:DB_Version_Key];
}
- (NSString *)DBCount {
return [[NSUserDefaults standardUserDefaults] objectForKey:DB_Count_Key];
}
// 數據庫版本控制主要方法
- (void)versionControlWithNewDBVersion:(NSString*)newDBVersion {
// 獲取舊版本號
NSString * version_old = YstenFriendDBManager_ValueOrEmpty([self DBVersion]);
// 獲取新版本號
NSString * version_new = [NSString stringWithFormat:@"%@", newDBVersion];
NSLog(@"dbVersionControl before: %@ after: %@",version_old,version_new);
NSMutableDictionary *migrationInfos = [NSMutableDictionary dictionary];
// 數據庫版本升級
if (version_old != nil && ![version_new isEqualToString:version_old] ) {
// 修改如今的表名添加後綴設置爲舊錶
[self sqliteChangeTableName_back];
// 取出舊錶中全部的字段
NSArray *oldTableColumns = [self sqliteOldTableColumnsWithTableName];
// 建立新表
[self initNewTables];
// 取出新表中的全部字段
NSArray *newTableColumns = [self sqliteNewTableColumnsWithTableName];
// 舊錶和新表對比
NSArray* publicColumns = [self publicColumnsWithOldTableColumns:oldTableColumns newTableColumns:newTableColumns];
// 遍歷相同字段存字典
for (NSString* newTableName in newTableColumns) {
for (NSString* oldTableName in oldTableColumns) {
if ([newTableName containsString:oldTableName]) {
if (publicColumns.count > 0) {
[migrationInfos setObject:publicColumns forKey:newTableName];
}
}
}
// 數據遷移處理
[self sqilte3MigrationToNewTables:migrationInfos];
// 保存新版本數據庫版本號 ps andDBCount廢棄
[self setDBVersion:newDBVersion andDBCount:@"10"];
}
}
}
// 獲取數據庫中舊的表
- (NSArray*)sqliteExistsTables {
_database= [self openDB];
__block NSMutableArray<NSString*>* existsTables = [NSMutableArray array];
NSString* sql = [NSString stringWithFormat:@"SELECT * from sqlite_master WHERE type='table' AND name LIKE '%@'",'表名'];
char *err;
sqlite3_stmt *pStmt = 0x00;
int result= sqlite3_exec(_database, [sql UTF8String], NULL, NULL, &err);
if (result==SQLITE_OK) {
char *nameData = (char *)sqlite3_column_text(pStmt, 1);
NSString *columnName = [[NSString alloc] initWithUTF8String:nameData];
[existsTables addObject:columnName];
}
[self closeDB];
return existsTables;
}
// 獲取jiu表中全部字段名稱
-(NSArray*) sqliteOldTableColumnsWithTableName{
_database = [self openDB];
NSMutableArray* tableColumes = [[NSMutableArray alloc]init];
sqlite3_stmt *pStmt = 0x00;
NSString* tableName = [NSString stringWithFormat:@"%@_bak",'表名'];
NSString* sql = [NSString stringWithFormat:@"PRAGMA table_info('%@')", tableName];
sqlite3_prepare_v2(_database, sql.UTF8String, -1, &pStmt, nil);
while (sqlite3_step(pStmt) == SQLITE_ROW) {
char *nameData = (char *)sqlite3_column_text(pStmt, 1);
NSString *columnName = [[NSString alloc] initWithUTF8String:nameData];
[tableColumes addObject:columnName];
}
[self closeDB];
return tableColumes;
}
// 修改表名後綴加old
-(void) sqliteChangeTableName_back{
_database = [self openDB];
char *err;
sqlite3_stmt *pStmt = 0x00;
NSString* sql = [NSString stringWithFormat:@"ALTER TABLE '%@' RENAME TO '%@_bak'", '表名','表名'];
int result = sqlite3_exec(_database, [sql UTF8String], NULL, pStmt, &err);
if (result == SQLITE_OK) {
NSLog(@"修改表名成功(%@)",'表名');
}
[self closeDB];
}
// 須要重寫該方法
-(void) initNewTables {
// 從新定義本身須要的表
}
// 獲取新表中全部字段名稱
-(NSArray*) sqliteNewTableColumnsWithTableName{
_database = [self openDB];
NSMutableArray* tableColumes = [[NSMutableArray alloc]init];
sqlite3_stmt *pStmt = 0x00;
NSString* sqlstring = [NSString stringWithFormat:@"PRAGMA table_info('%@')",'表名'];
sqlite3_prepare_v2(_database, sqlstring.UTF8String, -1, &pStmt, nil);
while (sqlite3_step(pStmt) == SQLITE_ROW) {
char *nameData = (char *)sqlite3_column_text(pStmt, 1);
NSString *columnName = [[NSString alloc] initWithUTF8String:nameData];
[tableColumes addObject:columnName];
}
[self closeDB];
return tableColumes;
}
// 提取新表和舊錶的共同表字段,表字段相同列的才須要進行數據遷移處理
- (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;
}
// 刪除舊錶
-(void)sqlite3DropOldTables:(NSString *)oldTableName {
_database = [self openDB];
NSString* sql = [NSString stringWithFormat:@"DROP TABLE IF EXISTS %@", oldTableName];
char *err;
int result= sqlite3_exec(_database, [sql UTF8String], NULL, NULL, &err);
if (result==SQLITE_OK) {
NSLog(@"刪除舊錶成功");
}else {
NSLog(@"刪除舊錶失敗");
}
[self closeDB];
}
- (NSString*)ystStringForColumn:(NSString*)columnName {
return [self ystStringForColumnIndex:[self ystColumnIndexForName:columnName]];
}
- (NSString *)ystStringForColumnIndex:(int)columnIdx {
sqlite3_stmt *pStmt = 0x00;
if (sqlite3_column_type(pStmt, columnIdx) == SQLITE_NULL || (columnIdx < 0) || columnIdx >= sqlite3_column_count(pStmt)) {
return nil;
}
const char *c = (const char *)sqlite3_column_text(pStmt, columnIdx);
if (!c) {
// null row.
return nil;
}
return [NSString stringWithUTF8String:c];
}
- (int)ystColumnIndexForName:(NSString*)columnName {
columnName = [columnName lowercaseString];
NSNumber *n = [[self columnNameToIndexMap] objectForKey:columnName];
if (n != nil) {
return [n intValue];
}
NSLog(@"Warning: I could not find the column named '%@'.", columnName);
return -1;
}
-(NSMutableDictionary *)columnNameToIndexMap{
if (_columnNameToIndexMap) {
sqlite3_stmt *pStmt = 0x00;
int columnCount = sqlite3_column_count(pStmt);
_columnNameToIndexMap = [[NSMutableDictionary alloc] initWithCapacity:(NSUInteger)columnCount];
int columnIdx = 0;
for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
[_columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx]
forKey:[[NSString stringWithUTF8String:sqlite3_column_name(pStmt, columnIdx)] lowercaseString]];
}
}
return _columnNameToIndexMap;
}
// 數據遷移處理
-(void)sqilte3MigrationToNewTables:(NSMutableDictionary *)migrationInfos{
_database = [self openDB];
[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:@", "];
}
}
NSString *sqlString = [NSString stringWithFormat:@"INSERT INTO '%@' ('%@') SELECT ('%@') FROM '%@_bak';",newTableName,colunmsString,colunmsString,newTableName];
char *err;
int result= sqlite3_exec(self->_database, [sqlString UTF8String], NULL, NULL, &err);
if (result==SQLITE_OK) {
NSLog(@"數據遷移處理成功");
}else{
NSLog(@"數據遷移處理失敗");
}
}];
[self closeDB];
}
複製代碼
PS:本文不純是本人思路,有bd來的,有fmdb封裝的,集合了小弟的思想,有那些low或者不足請不吝賜教,如說你罵我,我就打死你。數據庫