最近在弄项目的时候,须要多线程读写数据库,以前用的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
喜欢的打颗星
参考文章和项目
得找找了,参考了好几我的的代码