美文网首页
二、数据库之FMDB简介

二、数据库之FMDB简介

作者: Dosun | 来源:发表于2017-03-23 16:30 被阅读58次

项目中使用 ARC 还是 MRC,对使用 FMDB 都没有任何影响,FMDB 会在编译项目时自动匹配。

一、类使用

  1. FMDatabase: 代表单个数据库,用它来执行SQL语句。
  2. FMResultSet: 代表数据库的查询。
  3. FMDatabaseQueue:如果数据库在多线程要进行查询和更新,就使用FMDatabaseQueue这个类,

二、数据库的创建

FMDatabase类可以通过数据库路径来创建数据库,如下有三种方式得到数据路径
1、系统路径: 在磁盘上没有文件,如果上磁盘上没有数据库文件,FMDatabase会为我们创建。
2、空的字符串:如果数据库的路径是空字符串时,数据库将放在沙盒中temporary,如果数据库没有连接时,数据库将会被删除。
3、NULL的数据库路径:如果数据库路径是NULL,数据库会被创建,但是数据库没有连接时,数据库将会被删除。

NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"tmp.db"];
FMDatabase *db = [FMDatabase databaseWithPath:path];

三、打开数据库

在使用数据库之前,一定要打开数据库,果没有足够的资源和权限来打开\创建数据库,数据库会打开失败。

//当数据打开失败时,作为处理
if (![db open]) 
{
    db = nil;
    return;
}

三、数据库更新

除了SELECT语句外,所有的SQL语句都是更新,更新包括CREATE, UPDATE, INSERT, ALTER, COMMIT, BEGIN, DETACH, DELETE, DROP, END, EXPLAIN, VACUUM, and REPLACE 声明(甚至更多)。如果SQL语句没有SELECT ,那么该SQL语句是更新。执行更新SQL语句时,会返回单个数值如BOOL。
执行更新语句后会返回一个 BOOL 值,返回 YES 表示执行更新语句成功,返回 NO 表示出现错误,可以通过调用 -lastErrorMessage 和 -lastErrorCode 方法获取更多错误信息。
关于SQL语句的使用,一、数据库之SQL语句;

四、数据库查询

用-executeQuery...方法来查询数据库内容。如果查询数据成功会返回FMResultSet,否则返回是一个空。-lastErrorMessage 和 -lastErrorCode方法查找失败原因。
为了得到数据库查询的结果,使用while循环,在FMDB中可以轻松的实现。

FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"];
while ([s next]) {
    //retrieve values for each record
}

即使只需要获取一个数据,也还是必须在访问查询结果前调用 -[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:
    这些方法都有一个 {type}ForColumnIndex: 变体,是基于列的位置来查询数据。

通常情况下,一个 FMResultSet 没有必要手动 -close,因为结果集合 (result set) 被释放或者源数据库关闭会自动关闭。
五、关闭数据库
当完成数据库的查询和更新时,需要调用 -close方法去关闭数据库。

[db close];

六、事务

通过合理的方法或者执行 begin/end transaction语句,FMDatabase可以开始和提交事务。

七、数据库批量语句和操作

可以用FMDatabase 的executeStatements:withResul-tBlock: 方法中执行多个字符串语句。

NSString *sql = @"create table bulktest1 (id integer primary key autoincrement, x text);"
                 "create table bulktest2 (id integer primary key autoincrement, y text);"
                 "create table bulktest3 (id integer primary key autoincrement, z text);"
                 "insert into bulktest1 (x) values ('XXX');"
                 "insert into bulktest2 (y) values ('YYY');"
                 "insert into bulktest3 (z) values ('ZZZ');";

success = [db executeStatements:sql];

sql = @"select count(*) as count from bulktest1;"
       "select count(*) as count from bulktest2;"
       "select count(*) as count from bulktest3;";

success = [self.db executeStatements:sql withResultBlock:^int(NSDictionary *dictionary) {
    NSInteger count = [dictionary[@"count"] integerValue];
    XCTAssertEqual(count, 1, @"expected one record for dictionary %@", dictionary);
    return 0;
}];

八、数据的处理
给FMDB提供SQL语句时,执行语句前不要尝试处理任何值,应该参照如下的写法。

INSERT INTO myTable VALUES (?, ?, ?, ?)

?可以被SQLite识别,并将它作为一个占位符。FMDB 执行语句的方法都接受多个参数 (比如 NSArray,NSDict-ionary,va_list),并将它们转义成正确数值。
在Objcetive-C中SQL用?作为占位符。

NSInteger identifier = 42;
NSString *name = @"Liam O'Flaherty (\"the famous Irish author\")";
NSDate *date = [NSDate date];
NSString *comment = nil;

BOOL success = [db executeUpdate:@"INSERT INTO authors (identifier, name, date, comment) VALUES (?, ?, ?, ?)", @(identifier), name, date, comment ?: [NSNull null]];
if (!success) {
    NSLog(@"error = %@", [db lastErrorMessage]);
}

Fundamental 类型的数据,如identifier是整形,整形应该将转成NSNumber,如上面代码用@将整形转化成NSN-umber。或者用[NSNumber numberWithInt:identi-fier]方法将整形转化成NSNumber。
同样,SQL NULL 值应该是插入[NSNull null],如上面代码中comment可能为空,使用comment ?: [NSNull null]语句,如果comment 不为空时,将插入字符串,否则则插入[NSNull null];

或者,可以用使用如下语句

INSERT INTO authors (identifier, name, date, comment) VALUES (:identifier, :name, :date, :comment)

参数一定要是有冒号。SQLite本身支持其他的符号,在字典的键前面有冒号,一定不能在字典前面用冒号

NSDictionary *arguments = @{@"identifier": @(identifier), @"name": name, @"date": date, @"comment": comment ?: [NSNull null]};
BOOL success = [db executeUpdate:@"INSERT INTO authors (identifier, name, date, comment) VALUES (:identifier, :name, :date, :comment)" withParameterDictionary:arguments];
if (!success) {
    NSLog(@"error = %@", [db lastErrorMessage]);
}

最重要一点是,SQL语句中不要用NSString方法给拼接字符串,如stringWithFormat。

九、FMDatabaseQueue 和线程安全

FMDatabase 这个类是线程不安全的,在多线程中使用 FMDatabase 单例是极其错误做法。不能在多线程的环境中对数据库 FMDatabase 进行读写,会出现奔溃或者异常,因为你不能保证你读数据的同时另外一条线程不在写数据。因此不能在多线程中使用FMDatabase 单例。
相反使用在多线程中作用FMDatabaseQueue。用FMDatabaseQueue单例和在多个线程中使用它。FMDatabaseQueue单例是跨线程是同步的。如下是如何使用它。

//创建自己的队列
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];

//使用FMDatabaseQueue
[queue inDatabase:^(FMDatabase *db) {
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @1];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @2];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @3];

    FMResultSet *rs = [db executeQuery:@"select * from foo"];
    while ([rs next]) {
        …
    }
}];

FMDatabaseQueue在事务中的使用

[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @1];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @2];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @3];

    if (whoopsSomethingWrongHappened) {
        *rollback = YES;
        return;
    }
    // etc ...
}];

如上是翻译自官方文档,和参考FMDB 使用方法,其中Swift部分略去,请见谅;
由于时间有限,不足之处,请指正,感谢!

相关文章

网友评论

      本文标题:二、数据库之FMDB简介

      本文链接:https://www.haomeiwen.com/subject/pznznttx.html