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阅读 198,322评论 5 465
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,288评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,227评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,015评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,936评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,534评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,995评论 3 389
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,616评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,907评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,923评论 2 315
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,741评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,525评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,016评论 3 301
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,141评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,453评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,054评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,249评论 2 339

推荐阅读更多精彩内容