FMDB使用

Github中的介绍

使用

FMDB中主要有三个类:

  1. FMDatabase - 代表单独的一个SQLite数据库。用来执行SQL语句。
  2. FMResultSet - 代表FMDatabase查询的结果。
  3. FMDatabaseQueue - 如果你想在多线程中执行查询和更新,你就会使用到这个类。

创建数据库

要使用一个路径来创建一个FMDatabase。路径有如下三种方式:

  1. 文件系统路径。磁盘上的文件不一定要存在。如果不存在,就会创建。
  2. 一个空的字符串(@"")。在一个临时的位置创建一个空的数据库。当FMDatabase的连接被关闭的时候,数据库会被销毁。
  3. NULL。一个in-memory的数据库会被创建。当FMDatabase的连接被关闭的时候,数据库会被销毁。
FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];

打开数据库

在和数据库交互前,必须打开数据库。可能会打开失败:

if (![db open]) {
    [db release];
    return;
}

执行更新

除了SELECT语句,其它的SQL语句都被认为是更新(update)。包括CREATE, UPDATE, INSERT, ALTER, COMMIT, BEGIN, DETACH, DELETE, DROP, END, EXPLAIN, VACUUM, 和 REPLACE 。基本上,如果你的SQL语句不是以SELECT开头,就都是更新语句。

执行更新,返回一个BOOL值。返回YES表示更新成功,返回NO表示有错误发生。你可以调用-lastErrorMessage-lastErrorCode方法来获取更多的信息。

执行查询

通过-executeQuery...其中之一的方法来执行一个SELECTSELECT一个查询。
执行查询成功,返回的是一个FMResultSet对象,失败就返回nil
使用while()循环来遍历结果。

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:

Typically, there’s no need to -close an FMResultSet yourself, since that happens when either the result set is deallocated, or the parent database is closed.

关闭

当完成数据库的查询和更新之后,你应该-close数据库FMDatabase的连接。

[db close];

事务

FMDatabase can begin and commit a transaction by invoking one of the appropriate methods or executing a begin/end transaction statement.

Multiple Statements and Batch Stuff

使用FMDatabaseexecuteStatements:withResultBlock:方法,来执行多个语句:

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;
}];

数据处理(Data Sanitization)

要使用标准的SQLite绑定语法:

INSERT INTO myTable VALUES (?, ?, ?)

表示被插入值得占位符。

相应的,你也可以使用named parameters syntax:

INSERT INTO myTable VALUES (:id, :name, :value)

参数必须以冒号开头。SQLite支持其它的字符,但是字典的keys带有一个冒号的前缀,所有在字典的keys中不要包含冒号:

NSDictionary *argsDict = [NSDictionary dictionaryWithObjectsAndKeys:@"My Name", @"name", nil];
[db executeUpdate:@"INSERT INTO myTable (name) VALUES (:name)" withParameterDictionary:argsDict];

另外,请不要这样做:

[db executeUpdate:[NSString stringWithFormat:@"INSERT INTO myTable VALUES (%@)", @"this has \" lots of ' bizarre \" quotes '"]];

相反,应该这么做:

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @"this has \" lots of ' bizarre \" quotes '"];

提供给-executeUpdate:方法的参数都必须是对象。下面的就是错的,会导致崩溃:

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", 42];

插入一个数字的正确方法是使用NSNumber对象:

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:42]];

另一种方法是,使用-execute*WithFormat:,类似于字符串替换:

[db executeUpdateWithFormat:@"INSERT INTO myTable VALUES (%d)", 42];

使用FMDatabaseQueue和线程安全

在多个线程中使用一个FMDatabase的实例是个坏主意。

So don’t instantiate a single FMDatabase object and use it across multiple threads.

要使用FMDatabaseQueue。下面是使用的方法:
首先,创建queue

FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];

然后,这样使用它:

[queue inDatabase:^(FMDatabase *db) {
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; FMResultSet *rs = [db executeQuery:@"select * from foo"]; while ([rs next]) { … } }];

把things包裹在一个事务里,可以这样做:

[queue inTransaction:^(FMDatabase *db, BOOL *rollback) { [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; if (whoopsSomethingWrongHappened) { *rollback = YES; return; } // etc… [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]]; }];

你可能感兴趣的:(FMDB使用)