前言数据库
FMDB库虽然进一步对封装了系统自己的SQLite操做逻辑,可是使用过的朋友都知道,你仍是须要写一堆的SQL操做语句才能进行操做并且并不支持实体操做。为了解决这些问题就须要对FMDB进行二次封装,支持实体操做以及简化其操做逻辑。架构
大致的思路;框架
(1)经过runtime获取model实体的属性变量名充当数据表的字段名,属性变量类型充当数据表字段类型,实体的类名充当数据表的名称;atom
(2)封装基本的数据库操做逻辑(增删改查),经过拼接SQL字符串,而后采用FMDB第三方库操做SQL语句。设计
总体设计架构主要的两个部分,数据库建立管理和数据表操做管理;版本控制
(1)统一管理的服务类DBService,拥有数据库管理对象,提供操做数据库的外部接口,相似外观模式。code
(2)数据库管理,经过JSDatabase基类实现数据库建立以及注册数据表的生成,通常使用方法是经过子类继承该类配置数据库存储路径,并拥有管理全部表对象的权限;对象
(3)数据表操做管理,经过JSContentTable基类实现全部的逻辑,每个子类继承该类对应一个操做数据表的对象,这些表管理对象由数据库管理对象管理(也就是继承JSDatabase的子类);继承
设计思路参照.Net的EF框架的设计思路,表对象对应数据表,而DBService就至关于EF的DataContext数据库上下文管理对象,经过DBService能够完成整个数据库全部表的CURD操做。索引
数据库管理基类,负责建立数据库以及建立全部数据表和建立版本控制表进行数据库版本升级,而且经过子类设置数据库存放路径建立数据库,并执行createAllTable生成数据表。
#import "JSDatabase.h" #import "FMDatabase.h" #import "FMDatabaseQueue.h" @interface JSDatabase () @property (nonatomic, copy) NSMutableArray *tables; @property (nonatomic, strong) FMDatabaseQueue *dbQueue; @property (nonatomic, copy) NSString *dbPath; @end @implementation JSDatabase - (void)dealloc { [self.dbQueue close]; } // 设置数据库版本 - (NSInteger)getDBVersion { return 1; } // 建立数据库并生成全部数据表; - (void)createPath:(NSString *)dbPath mode:(JsDatabaseMode)mode registerTable:(void (^)())registerTable { self.dbPath = dbPath; if (mode == JsDatabaseModeRead) { self.dbQueue = [FMDatabaseQueue databaseQueueWithPath:dbPath flags:SQLITE_OPEN_READONLY]; } else if (mode == JsDatabaseModeWrite) { // FMDatabaseQueue经过gcd建立数据库; self.dbQueue = [[FMDatabaseQueue alloc] initWithPath:dbPath]; } if (registerTable) { registerTable(); } // 生成全部数据表; [self.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { NSString *version = [self getVersion:db]; if (!version) { [self createDBVersionTable:db]; [self createAllTable:db]; [self updateDBVersion:db]; } else if ([version integerValue] != [self getDBVersion]) { [self updateDB:db]; [self updateDBVersion:db]; } }]; } // 建立数据表; - (void)createAllTable:(FMDatabase *)aDB { [self.tables enumerateObjectsUsingBlock:^(JSContentTable * _Nonnull objTable, NSUInteger idx, BOOL * _Nonnull stop) { [objTable createTable:aDB]; }]; } /* 数据库版本控制,经过jsdb_version管理,当数据表结构发生变化时,经过更新getDBVersion中的版本号值,执行updateDB方法进行数据表的数据迁移工做,迁移完成后再执行updateDBVersion更新jsdb_version表中的version字段的值,表示数据库迁移成功。 */ // 取得jsdb_version数据表中最新的版本 - (NSString *)getVersion:(FMDatabase *)aDB { NSString *version = nil; FMResultSet *resultSet = [aDB executeQuery:@"select version from jsdb_version where name = 'version'"]; while ([resultSet next]) { version = [resultSet stringForColumnIndex:0]; } [resultSet close]; return version; } // 更新数据库版本为当前最新版本 - (void)updateDBVersion:(FMDatabase *)aDB { NSString *version = [self getVersion:aDB]; if (version) { [aDB executeUpdate:@"update jsdb_version set version = ? where name = 'version'", @([self getDBVersion])]; } else { [aDB executeUpdate:@"insert into jsdb_version (name, version) values (?,?)", @"version", @([self getDBVersion])]; } } // 刚生成数据库时,建立数据库版本控制表jsdb_version - (void)createDBVersionTable:(FMDatabase *)aDB { [aDB executeUpdate:@"create table if not exists jsdb_version (version vachar (20) ,name varchar (10))"]; } // 数据库版本发生更新时,更新全部表的结构并迁移旧数据 - (void)updateDB:(FMDatabase *)aDB { [self.tables enumerateObjectsUsingBlock:^(JSContentTable * _Nonnull objTable, NSUInteger idx, BOOL * _Nonnull stop) { [objTable updateDB:aDB]; }]; } // 注册数据表; - (JSContentTable *)registerTableClass:(Class)tableClass { JSContentTable *table = [[tableClass alloc] init]; [table configTableName]; table.dbQueue = self.dbQueue; [self.tables addObject:table]; return table; } // 保存数据表对象 - (NSMutableArray *)tables { if (!_tables) { _tables = [[NSMutableArray alloc] init]; } return _tables; } @end
数据库子类,继承JSDatabase,负责配置数据库存放的路径以及管理全部的数据表;
#import "JSDatabase.h" #import "GradeTable.h" @interface DataClient : JSDatabase @property (nonatomic, strong, readonly) GradeTable *gradeTable; + (instancetype)database; - (void)construct; @end #import "DataClient.h" #import "JSDatabaseConfig.h" @interface DataClient () @property (nonatomic, strong) NSString *dbPath; @property (nonatomic, strong) GradeTable *gradeTable; @end @implementation DataClient + (instancetype)database { DataClient *dataClient = [[DataClient alloc] init]; [dataClient construct]; return dataClient; } - (void)construct { [self createPath:self.dbPath mode:JsDatabaseModeWrite registerTable:^{ self.gradeTable = (GradeTable *)[self registerTableClass:[GradeTable class]]; }]; } //// 数据库版本升级,重写getDBVersion替换版本号 //- (NSInteger)getDBVersion { // // return 2; //} - (NSString *)dbPath { if (!_dbPath) { NSString *dbPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:[JSDatabaseConfig config].dataBaseName]; _dbPath = dbPath; } return _dbPath; } @end
对于DBService以及数据表类,代码略;
(1)DBService主要是管理数据库,而且提供全部操做数据表的外部接口,方便使用;
(2)数据表类主要是管理数据表,好比增删改查,设置索引以及增长字段和删除字段等操做。