github链接地址 https://github.com/ccgus/fmdb
文顶http://www.cnblogs.com/wendingding/p/3871848.html>
http://www.sqlite.org/inmemorydb.html
1.FMDB
FMDB是iOS平台对 SQLite数据库框架以OC(面向对象)的方式进行封装的API.
2.FMDB 三大核心类
1. FMDatabase 一个FMDatabase 对象代表一个SQLite数据库,用来执行SQL语句。
2. FMResultSet 一个FMResultSet的对象,代表使用FMDatabase执行查询后的结果集。
3. FMDatabaseQueue 它用于在多线程中执行多个查询或更新,它是线程安全的。
3.数据库的创建
一个FMDatabase 对象可以由 SQLite数据库文件路径创建。这个路径可以由以下三种方式创建:
1.系统文件路径,这个路径不必一定存在,如果该路径不存在,它会帮你创建一个该路径的文件;
2.如果是一个空的字符串(@""),那么在当前路径下会为你创建一个暂时的空的数据库,当FMDatabase连接关闭时,数据库会被删除;
3.如果是null, 在内存中创建一数据库,当FMDatabase连接关闭时,数据库会被销毁。
-注释 :
1. NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"tmp.db"];
//创建数据库
FMDatabase *db = [FMDatabase databaseWithPath:path];
//打开数据库(在使用数据库之前,必须确保数据库是打开的)
if (![db open]){
// 打开失败
db = nil;return;
}
2.执行更新数据的语句
//SQL语句中除了SELECT语句,其他任何语句都有更新数据库的作用,包括(CREATE, UPDATE, INSERT, ALTER, COMMIT, BEGIN, DETACH, DELETE, DROP, END, EXPLAIN, VACUUM, and REPLACE)。意思是只要SQL语句不是SELECT开始的语句,都是更新语句。
3.执行查询
//SELECT语句通过执行一次executeQuery...方法进行一次查询。
//执行的查询语句,如果执行成功的返回值是一个FMResultSet集合,如果执行失败可以使用-lastErrorMessage和-lastErrorCode方法确定为什么查询失败。
//可以用while()循环遍历你的查询结果,
FMResultSet *resultSet = [db executeQuery:@"SELECT * FROM myTable"];
while ([resultSet next]){
// 检索每个值
}
// 在查询结果集时,即使你只需要其中一个值,你也必须调用-[FMResultSet next]这个方法,去查找其中的一个值
FMResultSet *s = [db executeQuery:@"SELECT COUNT(*) FROM myTable"];
if ([s next]) {
int totalCount = [s intForColumnIndex:0];
}
//FMResultSet 有很多不同的数据格式的方法去检索结果集中的数据:
intForColumn:
longForColumn:
longLongIntForColumn:
boolForColumn:
doubleForColumn:
stringForColumn:
dateForColumn:
dataForColumn:
dataNoCopyForColumn:
UTF8StringForColumnName:
objectForColumnName:
//通常情况下,不必手动关闭FMResultSet,因为当任何一个结果集被释放或者父数据库被关闭时,FMResultSet会自动关闭。
4.关闭数据库
// 当执行完数据库查询或者更新时,应该手动关闭数据库,调用d -close方法,关闭数据库后SQLite 将会释放在执行过程中获取的所有数据。
[db close];
5.数据处理
// FMDatabase 能够调用一定方法去开始或者结束处理数据
4. 多语句操作和批量处理数据
//使用 FMDatabase's executeStatements:withResultBlock: 的语句处理多个SQL语句
NSString *sql = @"create table test1 (id integer primary key autoincrement , x test );
create table test2 (id integer primary key autoincrement , y test );
insert into test1 (x) values ('XXX');
insert into test2 (y) values ('YYY');";// 创建表名分别为test1 、test2 、test 3的表,autoincrement 自动增量为主键;insert into 往表test1 插入数据
success = [db execteStatements:sql];
sql = @"select count(*) as count from test1;
select count(*) as count from test2";
success = [self.db execteStatements:sql withResultBlock:^int(NSDictionary *dictionary) {
NSInteger count = [dictionary[@"count"] integerValue];
return 0;
}];]
5.数据处理
// 如果FMDB的执行语句是SQL语句,那么在插入之前不需要做任何处理,只需要使用标准化的SQL语法的语句
// 插入数据的语法,?该字符在SQLite语句中被用来作为占位符,作为要插入的值,
INSERT INTO myTable VALUES (? ,?, ?, ?);
二、其他
1、优点:
使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码
对比苹果自带的Core Data框架,更加轻量级和灵活
提供了多线程安全的数据库操作方法,有效地防止数据混乱
2、FM Database这个类是线程不安全的,如果在多个线程中同时使用一个FMDatabase实例,会造成数据混乱等问题,为了保证线程安全,FMDB提供方便快捷的FMDatabaseQueue。
三、FMDB的一些实用的用法总结
1、 用一个唯一的主键来标记数据模型,可以更好的实现查询、插入、删除数据,这是最近做开发一个单机版的项目用到FMDB的总结。
总的来说,FMDB在项目中使用的话,还是相对比较简单的,就是处理复杂的逻辑关系时比较繁琐。
附上能够简单使用的FMDB的封装:
-
创建数据库
因为在工程中需要用到很多个数据库表,所以以不同的用户唯一的名称创建了不同的数据库,用以标记该数据库的唯一性,使在一个工程中数据的操作不会错乱。#import "FMDBDataManager.h" #import "FMDB.h" #import <objc/runtime.h> @implementation FMDBDataManager { FMDatabase *_fmdb; } - (instancetype)initPrivateWithDBName:(NSString *)DBname{ self = [super init]; if (self) { [self createDBWithName:DBname]; } return self; } - (instancetype)init { NSAssert(FALSE, @"FMDBDataManager 不能调用init创建对象,请使用单例方法获取。"); return nil; } // 数据库相关操作 - (void)createDBWithName:(NSString *)DBname { NSArray * documentsArray = NSSearchPathForDirectoriesInDomains(NSDocument Directory, NSUserDomainMask, YES); NSString * documentsPath = documentsArray.lastObject; NSString * dbPath = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.db",DBname]]; NSLog(@"数据库地址 = %@", documentsPath); _fmdb = [[FMDatabase alloc] initWithPath:dbPath]; if ([_fmdb open]) {} } /** 获取当前对象的所有属性 @param objcClass 对象 @return <#return value description#> */ - (NSArray *)getPropertiesFromClass: (Class)objcClass{ NSMutableArray *propertiesArr = [NSMutableArray array]; unsigned int propertiesCount = 0; objc_property_t * objcPropertyArray = class_copyPropertyList(objcClass, &propertiesCount); for (int idx = 0; idx < propertiesCount; idx ++ ) { objc_property_t property = objcPropertyArray[idx]; const char *propertyName = property_getName(property); NSString *nameStr = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]; [propertiesArr addObject:nameStr]; } return propertiesArr; } /** 获取当前对象的所有属性对应的值 @param objcClass 当前对象 @return <#return value description#> */ - (NSArray *)getAllValuesFromObject:(id)objc{ NSMutableArray * valuesArray = [NSMutableArray array]; NSArray * propArray = [self getPropertiesFromClass:[objc class]]; for (NSString * prop in propArray) { id value = [objc valueForKey:prop]; if (!value) { [valuesArray addObject:[NSNull null]]; } else { [valuesArray addObject:value]; } } return valuesArray; } #pragma mark ------------- Public Method ------------- static FMDBDataManager * dataManager = nil; static dispatch_once_t onceToken; + (instancetype)sharedManagerWithDBName:(NSString *)DBName{ dispatch_once(&onceToken, ^{ if (!dataManager) { dataManager = [[FMDBDataManager alloc] initPrivateWithDBName:DBName]; } }); return dataManager; } - (void)closeDB{ onceToken = 0; dataManager = nil; [_fmdb close]; } /** 创建数据库表 @param object 创建表所需对象 @param tableName 表名 @return <#return value description#> */ - (BOOL)createTableWithObject:(id)object tableName:(NSString *)tableName{ NSArray * propertiesArray = [self getPropertiesFromClass:[object class]]; NSString * propertiesStr = [propertiesArray componentsJoinedByString:@" , "]; propertiesStr = [propertiesStr stringByAppendingString:@" "]; NSString * createSql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@ (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, %@);", tableName, propertiesStr]; BOOL isSuccess = [_fmdb executeUpdate:createSql]; return isSuccess; } /** 插入某条数据 @param object 插入的对象 @param keyID 插入对象的在该表中的唯一ID @param tableName 插入表的表名,如果当前表存在,直接插入,如果当前表名的表不存在,先创建表再插入 @return 插入是否成功 */ - (BOOL)insertTableWithObject:(id)object withIdentifier:(NSString *)identifier tableName:(NSString *)tableName{ if ([self isExistWithIdentifiert:identifier tableName:tableName]) { return NO; } Class objcClass = [object class]; [self createTableWithObject:object tableName:tableName]; NSArray * propertiesArray = [self getPropertiesFromClass:objcClass]; NSString * propStr = [propertiesArray componentsJoinedByString:@", "]; NSArray * valuesArray = [self getAllValuesFromObject:object]; NSMutableArray * placeHolderArray = [NSMutableArray array]; for (NSString * prop in propertiesArray) { [placeHolderArray addObject:@"?"]; } NSString * placeHolderStr = [placeHolderArray componentsJoinedByString:@", "]; NSString * insertSql = [NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES (%@);", tableName, propStr, placeHolderStr]; BOOL isSuccess =[_fmdb executeUpdate:insertSql withArgumentsInArray:valuesArray]; if (isSuccess) { NSLog(@"数据插入成功 ========= %@", NSStringFromClass(objcClass)); } return isSuccess; } /** 判断当前标准是否存在该对象 @param identifier 查找对象的ID @param tableNam 查找表名 @return <#return value description#> */ - (BOOL)isExistWithIdentifiert:(NSString *)identifier tableName:(NSString *)tableName{ NSString * selectSql = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE identifier = '%@'", tableName, identifier]; FMResultSet * resultSet = [_fmdb executeQuery:selectSql]; while ([resultSet next]) { return YES; } return NO; } /** 获取当前表的所有数据 @param tableName 表名 @return 获取是否成功 */ - (NSArray *)getAllObjectFromWithClass:(Class)objcClass TabelName:(NSString *)tableName{ NSString * selectAllSql = [NSString stringWithFormat:@"SELECT * FROM %@", tableName]; FMResultSet * resultSet = [_fmdb executeQuery:selectAllSql]; NSMutableArray * objectsArray = [NSMutableArray array]; NSArray * propArray = [self getPropertiesFromClass:objcClass]; while ([resultSet next]) { id object = [[objcClass alloc] init]; for (NSString * prop in propArray) { id value = [resultSet objectForColumnName:prop]; [object setValue:value forKey:prop]; } [objectsArray addObject:object]; } return objectsArray; } /** 删除当前表中的某一个对象 @param keyID 删除的对象的ID @param tableName 表名 @return <#return value description#> */ - (BOOL)deleteTableRecordWithObject:(id)object withIdentifier:(NSString *)identifier withTableName:(NSString *)tableName{ if (![self isExistWithIdentifiert:identifier tableName:tableName]) { return NO; } NSArray * valueArray = [self getAllValuesFromObject:object]; NSString * deleteSql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE identifier = '%@'", tableName, identifier]; BOOL isSuccess = [_fmdb executeUpdate:deleteSql withArgumentsInArray:valueArray]; return isSuccess; } - (BOOL)deleteTableRecordWithTableName:(NSString *)tableName{ NSString * deleteSql = [NSString stringWithFormat:@"DELETE FROM %@ ", tableName]; BOOL isSuccess = [_fmdb executeUpdate:deleteSql]; return isSuccess; } /** 更新某个表中的某个对象 @param object 该对象 @param tableName 当前表名 @return <#return value description#> */ - (BOOL)uploadObjectFromWithIdentifier:(NSString *)identifier toProperty:(NSString *)property withNewValue:(NSString *)value withTableName:(NSString *)tableName{ // 获得新对象的属性、值 NSString *updataSql = [NSString stringWithFormat:@"UPDATE %@ SET %@ = %@ WHERE identifier = '%@'",tableName,property,value,identifier]; BOOL isSuccess = [_fmdb executeUpdate:updataSql]; if (isSuccess) { NSLog(@"数据更新成功"); } return isSuccess; }
用过FMDB 之后,觉得其实这个框架并不是很难,一般运用也只会用到一些简单的方法,我在使用的时候有很多需求不会写SQL语句的时候就去http://www.w3school.com.cn/sql/index.asp
然后执行久行了,大家可以尝试一下,有什么更好的运用和比较坑的地方都可以告诉我,毕竟坑不踩就不是坑了🐤。有点乱,以后再整理吧。😅
网友评论