iOS-FMDB 基础用法

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 
    
     @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
然后执行久行了,大家可以尝试一下,有什么更好的运用和比较坑的地方都可以告诉我,毕竟坑不踩就不是坑了。有点乱,以后再整理吧。

你可能感兴趣的:(iOS-FMDB 基础用法)