最近在弄項目的時候,須要多線程讀寫數據庫,以前用的SQlite遇到多線程就不給力,很容易出現ACCESS_BAD的問題,因而找了些資料,發現FMDB的FMDBQueue能夠比較容易的處理多線程的問題,因此就寫了個demoios
1,首先導入FMDB框架,能夠採用cocoapods 管理依賴git
對應的Podfile以下github
platform :ios, '7.0' pod 'AFNetworking', '~> 2.0' pod 'FMDB', '~>2.2' pod 'Masonry','~>0.6'
本身下載而後導入FMDB模塊也是能夠的sql
2,操做的學生類Student類有3個屬性,學生ID,學生姓名和年齡。數據庫
#import <Foundation/Foundation.h> @interface Student : NSObject @property (nonatomic,copy) NSString *studentID; @property (nonatomic,copy) NSString *studentName; @property (nonatomic,strong) NSNumber *studentAge; @end
3,建立GJFMDBQueueHelper的單例多線程
- (id)init { static id obj=nil; static dispatch_once_t onceToken; dispatch_once(&onceToken,^{ if ((obj =[super init])!=nil) { //建立表 [self createDatabaseTable]; } }); self=obj; return self; } + (id)allocWithZone:(struct _NSZone *)zone { // 裏面的代碼永遠只執行1次 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedHelper = [super allocWithZone:zone]; }); // 返回對象 return sharedHelper; } + (instancetype)sharedHelper { // 裏面的代碼永遠只執行1次 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedHelper = [[self alloc] init]; }); // 返回對象 return sharedHelper; } + (id)copyWithZone:(struct _NSZone *)zone { return sharedHelper; }
4,建立表框架
-(BOOL)createDatabaseTable { NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.sqlite",databaseName]]; self.dbQueue = [FMDatabaseQueue databaseQueueWithPath:filePath]; [self.dbQueue inDatabase:^(FMDatabase *db) { NSString *sql = @"CREATE TABLE IF NOT EXISTS t_students (student_id integer PRIMARY KEY AUTOINCREMENT,student_age integer NOT NULL,student_name text NOT NULL );"; BOOL result= [db executeUpdate:sql]; NSLog(@"%@",result?@"create table t_students success":@"create table t_students faiiled"); }]; return YES; }
5實現數據庫的增刪改查方法dom
增async
/*add */ -(BOOL)addNewStudentToDB:(Student *)student{ __block BOOL insertResult=NO; [self.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { [db open]; NSString *sqlString=[NSString stringWithFormat:@"INSERT INTO t_students (student_name,student_age) VALUES ('%@',%ld)", student.studentName, [student.studentAge integerValue]]; insertResult=[db executeUpdate:sqlString]; [db close]; }]; return insertResult; }
刪測試
/* delete */ -(BOOL)deleteStudentByStudentID:(NSString *)studentID{ __block BOOL result=NO; [self.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) { [db open]; NSString *sqlString=[NSString stringWithFormat:@"DELETE FROM t_students WHERE student_id = %ld",[studentID integerValue]]; result=[db executeUpdate:sqlString]; [db close]; }]; return result; }
改
/*update*/ -(BOOL)updateWithSQL:(NSString *)sqlString{ NSLog(@"update sql==%@",sqlString); __block BOOL updateResult=NO; [self.dbQueue inDatabase:^(FMDatabase *db) { [db open]; updateResult=[db executeUpdate:sqlString]; [db close]; }]; return updateResult; }
查
/*query */ -(NSArray *)modelsWithSQL:(NSString *)sqlString{ __block NSMutableArray *eventModels=[NSMutableArray array]; NSLog(@"query sql==%@",sqlString); [self.dbQueue inDatabase:^(FMDatabase *db) { [db open]; FMResultSet *rs = [db executeQuery:sqlString]; while ([rs next]) { // [eventModels addObject:[self modelFromRS :rs]]; } [db close]; }]; return eventModels; }
外部調用
在程序啓動的時候判斷是否有記錄,若是沒有的話,加入100條隨機的數據
GJFMDBQueueHelper *fmdbHelper=[GJFMDBQueueHelper sharedHelper]; NSArray *students=[fmdbHelper allStudents]; if (students.count==0) { NSArray *nameArray=@[@"Jim",@"Mike",@"Lucy",@"Jessica"]; for (int i=0; i<100; i++) { Student *student=[[Student alloc]init]; student.studentName=nameArray[i%(nameArray.count-1)]; student.studentAge=@(arc4random()%60+10); [fmdbHelper addNewStudentToDB:student]; } }
多線程測試
-(void)pressMTOButton{ NSLog(@"test mutiple thread operation"); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //read GJFMDBQueueHelper *fmdbHelper=[GJFMDBQueueHelper sharedHelper]; for (int i=0; i<100; i++) { Student *student= [fmdbHelper studentWithStudentID:[NSString stringWithFormat:@"%d",i]]; NSLog(@"111 first dispatch studnet==%@",student); } }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //write GJFMDBQueueHelper *fmdbHelper=[GJFMDBQueueHelper sharedHelper]; for (int i=0; i<100; i++) { Student *student=[[Student alloc]init]; student.studentName=@"StudentDemo"; student.studentAge=@11; NSLog(@"222 second dispatch operation ==%@",student); [fmdbHelper addNewStudentToDB:student]; } }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //delete GJFMDBQueueHelper *fmdbHelper=[GJFMDBQueueHelper sharedHelper]; for(int i=0;i<100;i++){ NSArray *students=[fmdbHelper studentsWithStudentName:@"StudentDemo"]; Student *student=students.firstObject; if (student) { [fmdbHelper deleteStudentByStudentID:student.studentID]; NSLog(@"333 third dispatch operation %@",student); } } }); }
完整項目代碼請在github中查看
https://github.com/knight314/FMDBStudentsDemo
喜歡的打顆星
參考文章和項目
得找找了,參考了好幾我的的代碼