IOS:FMDB使用databaseQueue实现数据库操作线程安全

sqlite数据库是ios开发中经常使用到的数据持久化方案,因为项目需求的不同,对数据库操作的要求也不同。

由于最近使用sqlite时,有一些地方需要频繁的更新,这时在多线程操作时,其他线程访问数据库会造成程序崩溃,因为之前的框架里设计的数据库管理工具类采用的是单例模式,这样在多线程操作同一个数据库时很容易引起冲突,导致程序崩溃,所以开始寻找多线程下线程安全的办法。

其实FMDB本身已经对多线程做了考虑,FMDatabaseQueue就是为了解决数据库操作线程安全的,只是由于之前框架集成的单例操作,并且没有设计多线程访问,所以并没有发生这个问题。

FMDatabaseQueue解决线程安全的操作方法:

FMDatabaseQueue使用下面这个函数对数据库进行操作,通过描述可知,这样等于是把数据库的操作放到一个串行队列中,从而保证不会在同一时间对数据库做改动。

/**?Synchronously?perform?database?operations?on?queue.

?@param?block?The?code?to?be?run?on?the?queue?of?`FMDatabaseQueue`

?*/ ?

-?(void)inDatabase:(void?(^)(FMDatabase?*db))block;

FMDatabaseQueue要使用单例创建,这样多线程调用时,数据库操作使用一个队列,保证线程安全。

@interface?DBHelper?:?NSObject??

/**

?*??数据库操作队列

?*/?

@property(nonatomic,retain,readonly)FMDatabaseQueue *dbQueue;/** * 获取数据库管理类单例 */+(DBHelper *)sharedHelper;

在.m中实现单例创建(不做赘述),并重写dbQueue的get方法

//lazy?load??

-(FMDatabaseQueue?*)dbQueue{??

if?(!_dbQueue)?{??

_dbQueue?=?[FMDatabaseQueue?databaseQueueWithPath:DB_PATH];??

????}??

return?_dbQueue;??

}?

操作数据库时,通过单例的dbQueue在block内执行SQL操作,block属于同步执行,执行完之后才会跳出执行操作之后的语句

DBHelper?*dbHelper?=?[DBHelper?sharedHelper];??

__blockBOOL?res?=?NO;??

[dbHelper.dbQueue?inDatabase:^(FMDatabase?*db)?{??

NSString?*sql?=?[NSString?stringWithFormat:@"INSERT?INTO?%@(%@)?VALUES?(%@);",?tableName,?keyString,?valueString];??

res?=?[db?executeUpdate:sql?withArgumentsInArray:insertValues];??

self.pk?=?res?[NSNumber?numberWithLongLong:db.lastInsertRowId].intValue:0;??

NSLog(res?@"插入成功":@"插入失败");??

????}];??

return?res;?

注意:因为队列是串行执行的,因此inDatabase的block并不能嵌套使用,这样会导致错误。

了解了多线程下使用FMDatabaseQueue的操作原理就可以创建一个管理类对模型数据的存取查删进行统一管理,可以使用工具类操作,也可以创建集成NSObject的子类进行管理,需要存取的模型类继承此子类即可。

代码:

#import?? <objc/runtime.h>

/**?SQLite五种数据类型?*/??

#define?SQLTEXT?????@"TEXT"??

#define?SQLINTEGER??@"INTEGER"??

#define?SQLREAL?????@"REAL"??

#define?SQLBLOB?????@"BLOB"??

#define?SQLNULL?????@"NULL"??

#define?PrimaryKey??@"primary?key"??

#define?primaryId???@"pk" ?


/**

?*??数据库对象的父类

?*/??

@interface?DBBaseModel?:?NSObject??


/**?主键?id?*/??

@property?(nonatomic,?assign)???int????????pk;??


@property(nonatomic,copy)NSString?*keyWord;?????????????????//查表的关键字字段??


/**?列名?*/??

@property?(retain,?readonly,?nonatomic)?NSMutableArray?????????*columeNames;??

/**?列类型?*/??

@property?(retain,?readonly,?nonatomic)?NSMutableArray?????????*columeTypes;??



#pragma?--mark?functions??

/**

?*??获取该类(模型)中的所有属性?runtime

?*

?*/??

+?(NSDictionary?*)getPropertys;??


/**?获取所有属性,包括主键?*/??

+?(NSDictionary?*)getAllProperties;??


/**?数据库中是否存在表?*/??

+?(BOOL)isExistInTable;??


/**?表中的字段*/??

+?(NSArray?*)getColumns;??


/**?保存或更新

?*?如果不存在主键,保存,

?*?有主键,则更新

?*/??

-?(BOOL)saveOrUpdate;??

/**?保存单个数据?*/??

-?(BOOL)save;??

/**?批量保存数据?*/??

+?(BOOL)saveObjects:(NSArray?*)array;??

/**?更新单个数据?*/??

-?(BOOL)update;??

/**?批量更新数据*/??

+?(BOOL)updateObjects:(NSArray?*)array;??

/**?删除单个数据?*/??

-?(BOOL)deleteObject;??

/**?批量删除数据?*/??

+?(BOOL)deleteObjects:(NSArray?*)array;??

/**?通过条件删除数据?*/??

+?(BOOL)deleteObjectsByCriteria:(NSString?*)criteria;??

/**?清空表?*/??

+?(BOOL)clearTable;??


/**?查询全部数据?*/??

+?(NSArray?*)findAll;??


/**?通过主键查询?*/??

+?(instancetype)findByPK:(int)inPk;??




/**?查找某条数据?*/??

+?(instancetype)findFirstByCriteria:(NSString?*)criteria;??



//?值?为?通过?条件查找??-?返回数组中的第一个??

+?(instancetype)findWhereColoum:(NSString?*)coloum?equleToValue:(NSString?*)value;??


/**?通过条件查找数据

?*?这样可以进行分页查询?@"?WHERE?pk?>?5?limit?10"

?*/??

+?(NSArray?*)findByCriteria:(NSString?*)criteria;??


#pragma?mark?-?must?be?override?method??

/**

?*?创建表

?*?如果已经创建,返回YES

?*/??

+?(BOOL)createTable;??

/**?如果子类中有一些property不需要创建数据库字段,那么这个方法必须在子类中重写

?*/??

+?(NSArray?*)transients;??


//数据是否存在??

-?(BOOL?)isExsistObj;??


@end?


#import?"DBHelper.h"??



#define?dbTimeCount?@"recent_time"??



@implementation?DBBaseModel??


#pragma?mark?-?override?method??

+?(void)initialize??

{??

if?(self?!=?[DBBaseModel?self])?{??

[self?createTable];??

????}??

}??


-?(instancetype)init??

{??

self?=?[super?init];??

if?(self)?{??

NSDictionary?*dic?=?[self.class?getAllProperties];??

_columeNames?=?[[NSMutableArray?alloc]?initWithArray:[dic?objectForKey:@"name"]];??

_columeTypes?=?[[NSMutableArray?alloc]?initWithArray:[dic?objectForKey:@"type"]];??

????}??


return?self;??

}??


#pragma?mark?-?base?method??

/**

?*??获取该类的所有属性

?*/??

+?(NSDictionary?*)getPropertys??

{??

NSMutableArray?*proNames?=?[NSMutableArray?array];??

NSMutableArray?*proTypes?=?[NSMutableArray?array];??

NSArray?*theTransients?=?[[self?class]?transients];??

unsignedint?outCount,?i;??

objc_property_t?*properties?=?class_copyPropertyList([self?class],?&outCount);??

for?(i?=?0;?i?<?outCount;?i++)?{??

????????objc_property_t?property?=?properties[i];??

//获取属性名??

NSString?*propertyName?=?[NSString?stringWithCString:property_getName(property)?encoding:NSUTF8StringEncoding];??

if?([theTransients?containsObject:propertyName])?{??

continue;??

????????}??

[proNames?addObject:propertyName];??

//获取属性类型等参数??

NSString?*propertyType?=?[NSString?stringWithCString:?property_getAttributes(property)?encoding:NSUTF8StringEncoding];??

/*

?????????c?char?????????C?unsigned?char

?????????i?int??????????I?unsigned?int

?????????l?long?????????L?unsigned?long

?????????s?short????????S?unsigned?short

?????????d?double???????D?unsigned?double

?????????f?float????????F?unsigned?float

?????????q?long?long????Q?unsigned?long?long

?????????B?BOOL

?????????@?对象类型?//指针?对象类型?如NSString?是@“NSString”



?????????64位下long?和long?long?都是Tq

?????????SQLite?默认支持五种数据类型TEXT、INTEGER、REAL、BLOB、NULL

?????????*/??

if?([propertyType?hasPrefix:@"T@"])?{??

[proTypes?addObject:SQLTEXT];??

}else?if?([propertyType?hasPrefix:@"Ti"]||[propertyType?hasPrefix:@"TI"]||[propertyType?hasPrefix:@"Ts"]||[propertyType?hasPrefix:@"TS"]||[propertyType?hasPrefix:@"TB"])?{??

[proTypes?addObject:SQLINTEGER];??

}else?{??

[proTypes?addObject:SQLREAL];??

????????}??


????}??

????free(properties);??


return?[NSDictionary?dictionaryWithObjectsAndKeys:proNames,@"name",proTypes,@"type",nil];??

}??


/**?获取所有属性,包含主键pk?*/??

+?(NSDictionary?*)getAllProperties??

{??

NSDictionary?*dict?=?[self.class?getPropertys];??


NSMutableArray?*proNames?=?[NSMutableArray?array];??

NSMutableArray?*proTypes?=?[NSMutableArray?array];??

[proNames?addObject:primaryId];??

[proTypes?addObject:[NSString?stringWithFormat:@"%@?%@",SQLINTEGER,PrimaryKey]];??

[proNames?addObjectsFromArray:[dict?objectForKey:@"name"]];??

[proTypes?addObjectsFromArray:[dict?objectForKey:@"type"]];??


return?[NSDictionary?dictionaryWithObjectsAndKeys:proNames,@"name",proTypes,@"type",nil];??

}??


/**?数据库中是否存在表?*/??

+?(BOOL)isExistInTable??

{??

__blockBOOL?res?=?NO;??

DBHelper?*dbHelper?=?[DBHelper?sharedHelper];??

[dbHelper.dbQueue?inDatabase:^(FMDatabase?*db)?{??

NSString?*tableName?=?NSStringFromClass(self.class);??

res?=?[db?tableExists:tableName];??

????}];??

return?res;??

}??


+?(NSArray?*)getColumns??

{??

DBHelper?*dbHelper?=?[DBHelper?sharedHelper];??

NSMutableArray?*columns?=?[NSMutableArray?array];??

[dbHelper.dbQueue?inDatabase:^(FMDatabase?*db)?{??

NSString?*tableName?=?NSStringFromClass(self.class);??

FMResultSet?*resultSet?=?[db?getTableSchema:tableName];??

while?([resultSet?next])?{??

NSString?*column?=?[resultSet?stringForColumn:@"name"];??

[columns?addObject:column];??

????????}??

????}];??

return?[columns?copy];??

}??


/**

?*?创建表

?*?如果已经创建,返回YES

?*/??

+?(BOOL)createTable??

{??

FMDatabase?*db?=?[FMDatabase?databaseWithPath:[DBHelper?dbPath]];??

if?(![db?open])?{??

NSLog(@"数据库打开失败!");??

return?NO;??

????}??


NSString?*tableName?=?NSStringFromClass(self.class);??

NSString?*columeAndType?=?[self.class?getColumeAndTypeString];??

NSString?*sql?=?[NSString?stringWithFormat:@"CREATE?TABLE?IF?NOT?EXISTS?%@(%@);",tableName,columeAndType];??

if?(![db?executeUpdate:sql])?{??

return?NO;??

????}??


NSMutableArray?*columns?=?[NSMutableArray?array];??

FMResultSet?*resultSet?=?[db?getTableSchema:tableName];??

while?([resultSet?next])?{??

NSString?*column?=?[resultSet?stringForColumn:@"name"];??

[columns?addObject:column];??

????}??

NSDictionary?*dict?=?[self.class?getAllProperties];??

NSArray?*properties?=?[dict?objectForKey:@"name"];??

NSPredicate?*filterPredicate?=?[NSPredicate?predicateWithFormat:@"NOT?(SELF?IN?%@)",columns];??

//过滤数组??

NSArray?*resultArray?=?[properties?filteredArrayUsingPredicate:filterPredicate];??


for?(NSString?*column?in?resultArray)?{??

NSUInteger?index?=?[properties?indexOfObject:column];??

NSString?*proType?=?[[dict?objectForKey:@"type"]?objectAtIndex:index];??

NSString?*fieldSql?=?[NSString?stringWithFormat:@"%@?%@",column,proType];??

NSString?*sql?=?[NSString?stringWithFormat:@"ALTER?TABLE?%@?ADD?COLUMN?%@?",NSStringFromClass(self.class),fieldSql];??

if?(![db?executeUpdate:sql])?{??

return?NO;??

????????}??

????}??

[db?close];??

return?YES;??

}??


//数据是否存在??

-?(BOOL?)isExsistObj{??


id?otherPaimaryValue?=?[self?valueForKey:_keyWord];??


DBHelper?*dbHelper?=?[DBHelper?sharedHelper];??


__blockBOOL?isExist?=?NO;??


__blockDBBaseModel?*WeakSelf?=?self;??


[dbHelper.dbQueue?inDatabase:^(FMDatabase?*db)?{??


NSString?*tableName?=?NSStringFromClass(self.class);??

NSString?*sql?=?[NSString?stringWithFormat:@"SELECT?*?FROM?%@?WHERE?%@?=?'%@'",tableName,WeakSelf.keyWord,otherPaimaryValue];??


FMResultSet?*aResult?=?[db?executeQuery:sql];??


if([aResult?next]){??


isExist?=YES;??


}else{??


isExist?=NO;??

????????}??

[aResult?close];??

????}];??


return?isExist;??

}??


-?(BOOL)saveOrUpdate??

{??


BOOL?isExsist?=?[self?isExsistObj];??


if?(isExsist?)?{??


return??[self?update];??


}else{??


return?[self?save];??


????}??

}??





-?(BOOL)save??

{??

//保存修改时间??

NSTimeInterval?time?=?[[NSDate?date]timeIntervalSince1970];??

NSString?*str?=?[NSString?stringWithFormat:@"%.0f",time];??


NSString?*tableName?=?NSStringFromClass(self.class);??

NSMutableString?*keyString?=?[NSMutableString?string];??

NSMutableString?*valueString?=?[NSMutableString?string];??

NSMutableArray?*insertValues?=?[NSMutableArray??array];??

for?(int?i?=?0;?i?<?self.columeNames.count;?i++)?{??

NSString?*proname?=?[self.columeNames?objectAtIndex:i];??

if?([proname?isEqualToString:primaryId])?{??

continue;??

????????}??


[keyString?appendFormat:@"%@,",?proname];??

[valueString?appendString:@"?,"];??

id?value;??

if?([proname?isEqualToString:dbTimeCount])?{??

????????????value?=?str;??

}else{??

value?=?[self?valueForKey:proname];??

????????}??

if?(!value)?{??

value?=@"";??

????????}??

[insertValues?addObject:value];??

????}??


[keyString?deleteCharactersInRange:NSMakeRange(keyString.length?-?1,?1)];??

[valueString?deleteCharactersInRange:NSMakeRange(valueString.length?-?1,?1)];??


DBHelper?*dbHelper?=?[DBHelper?sharedHelper];??

__blockBOOL?res?=?NO;??

[dbHelper.dbQueue?inDatabase:^(FMDatabase?*db)?{??

NSString?*sql?=?[NSString?stringWithFormat:@"INSERT?INTO?%@(%@)?VALUES?(%@);",?tableName,?keyString,?valueString];??

res?=?[db?executeUpdate:sql?withArgumentsInArray:insertValues];??

self.pk?=?res?[NSNumber?numberWithLongLong:db.lastInsertRowId].intValue:0;??

NSLog(res?@"插入成功":@"插入失败");??

????}];??

return?res;??

}??


/**?批量保存用户对象?*/??

+?(BOOL)saveObjects:(NSArray?*)array??

{??

//判断是否是JKBaseModel的子类??

for?(DBBaseModel?*model?in?array)?{??

if?(![model?isKindOfClass:[DBBaseModel?class]])?{??

return?NO;??

????????}??

????}??


__blockBOOL?res?=?YES;??

DBHelper?*dbHelper?=?[DBHelper?sharedHelper];??

//?如果要支持事务??

[dbHelper.dbQueue?inTransaction:^(FMDatabase?*db,?BOOLBOOL?*rollback)?{??

for?(DBBaseModel?*model?in?array)?{??

//保存修改时间??

NSTimeInterval?time?=?[[NSDate?date]timeIntervalSince1970];??

NSString?*str?=?[NSString?stringWithFormat:@"%.0f",time];??


NSString?*tableName?=?NSStringFromClass(model.class);??

NSMutableString?*keyString?=?[NSMutableString?string];??

NSMutableString?*valueString?=?[NSMutableString?string];??

NSMutableArray?*insertValues?=?[NSMutableArray??array];??

for?(int?i?=?0;?i?<?model.columeNames.count;?i++)?{??

NSString?*proname?=?[model.columeNames?objectAtIndex:i];??

if?([proname?isEqualToString:primaryId])?{??

continue;??

????????????????}??

[keyString?appendFormat:@"%@,",?proname];??

[valueString?appendString:@"?,"];??

id?value;??

if?([proname?isEqualToString:dbTimeCount])?{??

????????????????????value?=?str;??

}else{??

value?=?[model?valueForKey:proname];??

????????????????}??

if?(!value)?{??

value?=@"";??

????????????????}??

[insertValues?addObject:value];??

????????????}??

[keyString?deleteCharactersInRange:NSMakeRange(keyString.length?-?1,?1)];??

[valueString?deleteCharactersInRange:NSMakeRange(valueString.length?-?1,?1)];??


NSString?*sql?=?[NSString?stringWithFormat:@"INSERT?INTO?%@(%@)?VALUES?(%@);",?tableName,?keyString,?valueString];??

BOOL?flag?=?[db?executeUpdate:sql?withArgumentsInArray:insertValues];??

model.pk?=?flag?[NSNumber?numberWithLongLong:db.lastInsertRowId].intValue:0;??

NSLog(flag?@"插入成功":@"插入失败");??

if?(!flag)?{??

res?=NO;??

*rollback?=YES;??

return;??

????????????}??

????????}??

????}];??

return?res;??

}??




/**?更新单个对象?*/??

-?(BOOL)update??

{??

//设置更新时间??

NSTimeInterval?time?=?[[NSDate?date]timeIntervalSince1970];??

NSString?*str?=?[NSString?stringWithFormat:@"%.0f",time];??


DBHelper?*dbHelper?=?[DBHelper?sharedHelper];??

__blockBOOL?res?=?NO;??


[dbHelper.dbQueue?inDatabase:^(FMDatabase?*db)?{??

NSString?*tableName?=?NSStringFromClass(self.class);??

id?primaryValue?=?[self?valueForKey:self.keyWord];??


NSMutableString?*keyString?=?[NSMutableString?string];??

NSMutableArray?*updateValues?=?[NSMutableArray??array];??

for?(int?i?=?0;?i?<?self.columeNames.count;?i++)?{??

NSString?*proname?=?[self.columeNames?objectAtIndex:i];??

if?([proname?isEqualToString:self.keyWord])?{??

continue;??

????????????}??

if([proname?isEqualToString:primaryId]){??


continue;??

????????????}??

[keyString?appendFormat:@"?%@=?,",?proname];??

id?value;??

if?([proname?isEqualToString:dbTimeCount])?{??

????????????????value?=?str;??

}else{??

value?=?[self?valueForKey:proname];??

????????????}??

if?(!value)?{??

value?=@"";??

????????????}??

[updateValues?addObject:value];??

????????}??


//删除最后那个逗号??

[keyString?deleteCharactersInRange:NSMakeRange(keyString.length?-?1,?1)];??

NSString?*sql?=?[NSString?stringWithFormat:@"UPDATE?%@?SET?%@?WHERE?%@?=??;",?tableName,?keyString,?self.keyWord];??

[updateValues?addObject:primaryValue];??

res?=?[db?executeUpdate:sql?withArgumentsInArray:updateValues];??

NSLog(res?@"更新成功":@"更新失败");??

????}];??

return?res;??

}??



/**?批量更新用户对象*/??

+?(BOOL)updateObjects:(NSArray?*)array??

{??

for?(DBBaseModel?*model?in?array)?{??

if?(![model?isKindOfClass:[DBBaseModel?class]])?{??

return?NO;??

????????}??

????}??

__blockBOOL?res?=?YES;??

DBHelper?*dbHelper?=?[DBHelper?sharedHelper];??

//?如果要支持事务??

[dbHelper.dbQueue?inTransaction:^(FMDatabase?*db,?BOOLBOOL?*rollback)?{??

for?(DBBaseModel?*model?in?array)?{??

NSTimeInterval?time?=?[[NSDate?date]timeIntervalSince1970];??

NSString?*str?=?[NSString?stringWithFormat:@"%.0f",time];??


NSString?*tableName?=?NSStringFromClass(model.class);??

id?primaryValue?=?[model?valueForKey:primaryId];??

if?(!primaryValue?||?primaryValue?<=?0)?{??

res?=NO;??

*rollback?=YES;??

return;??

????????????}??


NSMutableString?*keyString?=?[NSMutableString?string];??

NSMutableArray?*updateValues?=?[NSMutableArray??array];??

for?(int?i?=?0;?i?<?model.columeNames.count;?i++)?{??

NSString?*proname?=?[model.columeNames?objectAtIndex:i];??

if?([proname?isEqualToString:primaryId])?{??

continue;??

????????????????}??

[keyString?appendFormat:@"?%@=?,",?proname];??

id?value;??

if?([proname?isEqualToString:dbTimeCount])?{??

????????????????????value?=?str;??

}else{??

value?=?[model?valueForKey:proname];??

????????????????}??

if?(!value)?{??

value?=@"";??

????????????????}??

[updateValues?addObject:value];??

????????????}??


//删除最后那个逗号??

[keyString?deleteCharactersInRange:NSMakeRange(keyString.length?-?1,?1)];??

NSString?*sql?=?[NSString?stringWithFormat:@"UPDATE?%@?SET?%@?WHERE?%@=?;",?tableName,?keyString,?primaryId];??

[updateValues?addObject:primaryValue];??

BOOL?flag?=?[db?executeUpdate:sql?withArgumentsInArray:updateValues];??

NSLog(flag?@"更新成功":@"更新失败");??

if?(!flag)?{??

res?=NO;??

*rollback?=YES;??

return;??

????????????}??

????????}??

????}];??


return?res;??

}??


/**?删除单个对象?*/??

-?(BOOL)deleteObject??

{??

DBHelper?*dbHelper?=?[DBHelper?sharedHelper];??

__blockBOOL?res?=?NO;??

[dbHelper.dbQueue?inDatabase:^(FMDatabase?*db)?{??

NSString?*tableName?=?NSStringFromClass(self.class);??

id?primaryValue?=?[self?valueForKey:primaryId];??

if?(!primaryValue?||?primaryValue?<=?0)?{??

return?;??

????????}??

NSString?*sql?=?[NSString?stringWithFormat:@"DELETE?FROM?%@?WHERE?%@?=??",tableName,primaryId];??

res?=?[db?executeUpdate:sql?withArgumentsInArray:@[primaryValue]];??

NSLog(res?@"删除成功":@"删除失败");??

????}];??

return?res;??

}??


/**?批量删除用户对象?*/??

+?(BOOL)deleteObjects:(NSArray?*)array??

{??

for?(DBBaseModel?*model?in?array)?{??

if?(![model?isKindOfClass:[DBBaseModel?class]])?{??

return?NO;??

????????}??

????}??


__blockBOOL?res?=?YES;??

DBHelper?*dbHelper?=?[DBHelper?sharedHelper];??

//?如果要支持事务??

[dbHelper.dbQueue?inTransaction:^(FMDatabase?*db,?BOOLBOOL?*rollback)?{??

for?(DBBaseModel?*model?in?array)?{??

NSString?*tableName?=?NSStringFromClass(model.class);??

id?primaryValue?=?[model?valueForKey:primaryId];??

if?(!primaryValue?||?primaryValue?<=?0)?{??

return?;??

????????????}??


NSString?*sql?=?[NSString?stringWithFormat:@"DELETE?FROM?%@?WHERE?%@?=??",tableName,primaryId];??

BOOL?flag?=?[db?executeUpdate:sql?withArgumentsInArray:@[primaryValue]];??

NSLog(flag?@"删除成功":@"删除失败");??

if?(!flag)?{??

res?=NO;??

*rollback?=YES;??

return;??

????????????}??

????????}??

????}];??

return?res;??

}??


/**?通过条件删除数据?*/??

+?(BOOL)deleteObjectsByCriteria:(NSString?*)criteria??

{??

DBHelper?*dbHelper?=?[DBHelper?sharedHelper];??

__blockBOOL?res?=?NO;??

[dbHelper.dbQueue?inDatabase:^(FMDatabase?*db)?{??

NSString?*tableName?=?NSStringFromClass(self.class);??

NSString?*sql?=?[NSString?stringWithFormat:@"DELETE?FROM?%@?%@?",tableName,criteria];??

res?=?[db?executeUpdate:sql];??

NSLog(res?@"删除成功":@"删除失败");??

????}];??

return?res;??

}??


/**?清空表?*/??

+?(BOOL)clearTable??

{??

DBHelper?*dbHelper?=?[DBHelper?sharedHelper];??

__blockBOOL?res?=?NO;??

[dbHelper.dbQueue?inDatabase:^(FMDatabase?*db)?{??

NSString?*tableName?=?NSStringFromClass(self.class);??

NSString?*sql?=?[NSString?stringWithFormat:@"DELETE?FROM?%@",tableName];??

res?=?[db?executeUpdate:sql];??

NSLog(res?@"清空成功":@"清空失败");??

????}];??

return?res;??

}??


/**?查询全部数据?*/??

+?(NSArray?*)findAll??

{??

NSLog(@"db---%s",__func__);??

DBHelper?*dbHelper?=?[DBHelper?sharedHelper];??

NSMutableArray?*users?=?[NSMutableArray?array];??

[dbHelper.dbQueue?inDatabase:^(FMDatabase?*db)?{??

NSString?*tableName?=?NSStringFromClass(self.class);??

NSString?*sql?=?[NSString?stringWithFormat:@"SELECT?*?FROM?%@",tableName];??

FMResultSet?*resultSet?=?[db?executeQuery:sql];??

while?([resultSet?next])?{??

DBBaseModel?*model?=?[[self.class?alloc]?init];??

for?(int?i=0;?i<?model.columeNames.count;?i++)?{??

NSString?*columeName?=?[model.columeNames?objectAtIndex:i];??

NSString?*columeType?=?[model.columeTypes?objectAtIndex:i];??

if?([columeType?isEqualToString:SQLTEXT])?{??

[model?setValue:[resultSet?stringForColumn:columeName]?forKey:columeName];??

}else?{??

[model?setValue:[NSNumber?numberWithLongLong:[resultSet?longLongIntForColumn:columeName]]?forKey:columeName];??

????????????????}??

????????????}??

[users?addObject:model];??

????????????FMDBRelease(model);??

????????}??

????}];??


return?users;??

}??


/**?查找某条数据?*/??

+?(instancetype)findFirstByCriteria:(NSString?*)criteria??

{??

NSArray?*results?=?[self.class?findByCriteria:criteria];??

if?(results.count?<?1)?{??

return?nil;??

????}??


return?[results?firstObject];??

}??


+?(instancetype)findByPK:(int)inPk??

{??

NSString?*condition?=?[NSString?stringWithFormat:@"WHERE?%@=%d",primaryId,inPk];??

return?[self?findFirstByCriteria:condition];??

}??




/**?通过条件查找数据?*/??

+?(NSArray?*)findByCriteria:(NSString?*)criteria??

{??

DBHelper?*dbHelper?=?[DBHelper?sharedHelper];??

NSMutableArray?*users?=?[NSMutableArray?array];??

[dbHelper.dbQueue?inDatabase:^(FMDatabase?*db)?{??

NSString?*tableName?=?NSStringFromClass(self.class);??

NSString?*sql?=?[NSString?stringWithFormat:@"SELECT?*?FROM?%@??%@",tableName,criteria];??

FMResultSet?*resultSet?=?[db?executeQuery:sql];??

while?([resultSet?next])?{??

DBBaseModel?*model?=?[[self.class?alloc]?init];??

for?(int?i=0;?i<?model.columeNames.count;?i++)?{??

NSString?*columeName?=?[model.columeNames?objectAtIndex:i];??

NSString?*columeType?=?[model.columeTypes?objectAtIndex:i];??

if?([columeType?isEqualToString:SQLTEXT])?{??

[model?setValue:[resultSet?stringForColumn:columeName]?forKey:columeName];??

}else?{??

[model?setValue:[NSNumber?numberWithLongLong:[resultSet?longLongIntForColumn:columeName]]?forKey:columeName];??

????????????????}??

????????????}??

[users?addObject:model];??

????????????FMDBRelease(model);??

????????}??

????}];??


return?users;??

}??



//?值?为?通过?条件查找??-?返回数组中的第一个??

+?(instancetype)findWhereColoum:(NSString?*)coloum?equleToValue:(NSString?*)value{??


return?[[self?class]?findFirstByCriteria:[NSString?stringWithFormat:@"WHERE?%@='%@'",coloum,value]];??

}??



#pragma?mark?-?util?method??

+?(NSString?*)getColumeAndTypeString??

{??

NSMutableString*?pars?=?[NSMutableString?string];??

NSDictionary?*dict?=?[self.class?getAllProperties];??


NSMutableArray?*proNames?=?[dict?objectForKey:@"name"];??

NSMutableArray?*proTypes?=?[dict?objectForKey:@"type"];??


for?(int?i=0;?i<?proNames.count;?i++)?{??

[pars?appendFormat:@"%@?%@",[proNames?objectAtIndex:i],[proTypes?objectAtIndex:i]];??

if(i+1?!=?proNames.count)??

????????{??

[pars?appendString:@","];??

????????}??

????}??

return?pars;??

}??


-?(NSString?*)description??

{??

NSString?*result?=?@"";??

NSDictionary?*dict?=?[self.class?getAllProperties];??

NSMutableArray?*proNames?=?[dict?objectForKey:@"name"];??

for?(int?i?=?0;?i?<?proNames.count;?i++)?{??

NSString?*proName?=?[proNames?objectAtIndex:i];??

id??proValue?=?[self?valueForKey:proName];??

result?=?[result?stringByAppendingFormat:@"%@:%@\n",proName,proValue];??

????}??

return?result;??

}??


#pragma?mark?-?must?be?override?method??

/**?如果子类中有一些property不需要创建数据库字段,那么这个方法必须在子类中重写

?*/??

+?(NSArray?*)transients??

{??

return?@[];??

}??



@end??


DBHelper类

#import?"FMDB.h" ?

/**

?*??数据库管理工具

?*/??

@interface?DBHelper?:?NSObject??


@property(nonatomic,retain,readonly)FMDatabaseQueue?*dbQueue;??


/**

?*??获取数据库管理类单例

?*/??

+(DBHelper?*)sharedHelper;??


/**

?*??数据库文件沙盒地址

?*/??

+?(NSString?*)dbPath;??


@end??


#import?"DBHelper.h"??


@interface?DBHelper?()??


@property?(nonatomic,?retain)?FMDatabaseQueue?*dbQueue;??


@end??


@implementation?DBHelper??


+(DBHelper?*)sharedHelper{??

static?DBHelper?*instance?=?nil;??

static?dispatch_once_t?onceToken;??

if?(!instance)?{??

????????dispatch_once(&onceToken,?^{??

instance?=?[[super?allocWithZone:nil]init];??

????????});??

????}??

return?instance;??

}??

//lazy?load??

-(FMDatabaseQueue?*)dbQueue{??

if?(!_dbQueue)?{??

_dbQueue?=?[FMDatabaseQueue?databaseQueueWithPath:[[self?class]?dbPath]];??

????}??

return?_dbQueue;??

}??

//数据库地址??

+?(NSString?*)dbPath??

{??

NSString?*docsdir?=?[NSSearchPathForDirectoriesInDomains(?NSCachesDirectory,?NSUserDomainMask,?YES)?lastObject];??

NSFileManager?*filemanage?=?[NSFileManager?defaultManager];??

docsdir?=?[docsdir?stringByAppendingPathComponent:@"AppDataBase"];??

BOOL?isDir;??

BOOL?exit?=[filemanage?fileExistsAtPath:docsdir?isDirectory:&isDir];??

if?(!exit?||?!isDir)?{??

[filemanage?createDirectoryAtPath:docsdir?withIntermediateDirectories:YES?attributes:nil?error:nil];??

????}??

NSString?*dbpath?=?[docsdir?stringByAppendingPathComponent:@"TierTime.sqlite"];??

return?dbpath;??

}??


#pragma?--mark?保证单例不会被创建成新对象??

+(instancetype)alloc{??

NSAssert(0,?@"这是一个单例对象,请使用+(DBHelper?*)sharedHelper方法");??

return?nil;??

}??

+?(id)allocWithZone:(struct?_NSZone?*)zone??

{??

return?[DBHelper?sharedHelper];??

}??


-?(id)copyWithZone:(struct?_NSZone?*)zone??

{??

return?[DBHelper?sharedHelper];??

}??



@end??


使用示例:

PicCacheModel?*pic1?=?[[PicCacheModel?alloc]init];??

pic1.pic_name???????=?@"DefaultImage_0";??

pic1.pic_from_source?=?@"0";??

pic1.pic_path???????=?[NSString?stringWithFormat:@"%@.png",pic1.pic_name];??

pic1.pic_md5_str????=?[TRMD5?file_md5:MODEL_DEFAULT_SAVE_PATH(pic1.pic_path)];??


PicCacheModel?*pic2?=?[[PicCacheModel?alloc]init];??

pic2.pic_name???????=?@"DefaultImage_1";??

pic2.pic_from_source?=?@"0";??

pic2.pic_path???????=?[NSString?stringWithFormat:@"%@.png",pic2.pic_name];??

pic2.pic_md5_str????=?[TRMD5?file_md5:MODEL_DEFAULT_SAVE_PATH(pic2.pic_path)];??



PicCacheModel?*pic3?=?[[PicCacheModel?alloc]init];??

pic3.pic_name???????=?@"DefaultImage_2";??

pic3.pic_from_source?=?@"0";??

pic3.pic_path???????=?[NSString?stringWithFormat:@"%@.png",pic3.pic_name];??

pic3.pic_md5_str????=?[TRMD5?file_md5:MODEL_DEFAULT_SAVE_PATH(pic3.pic_path)];??




[pic1?saveOrUpdate];??

[pic2?saveOrUpdate];??

[pic3?saveOrUpdate];?

贴到这里,更多用法大家可以尝试一下

?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容