转自:http://blog.devtang.com/blog/2012/04/22/use-fmd

1
2
3
4
5
6
7
8
9
10
11
NSString* docsdir = [NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString* dbpath = [docsdir stringByAppendingPathComponent:@"user.sqlite"];
FMDatabase* db = [FMDatabase databaseWithPath:dbpath];
[db open];
FMResultSet *rs = [db executeQuery:@"select * from people"];
while ([rs next]) {
    NSLog(@"%@ %@",
        [rs stringForColumn:@"firstname"],
        [rs stringForColumn:@"lastname"]);
}
[db close];

能够看到,使用FMDB后的数据库代码清晰明了,比原生的API优雅多了。另外,FMDB同时兼容ARC和非ARC工程,会自动根据工程配置来调整相关的内存管理代码。git

使用说明

该使用说明主要翻译自fmdb的github项目说明文档: https://github.com/ccgus/fmdbgithub

引入相关文件

首先将FMDB从github上clone下来,而后将如下文件copy到你的工程中:sql

1
2
3
4
5
6
7
8
9
10
FMDatabase.h
FMDatabase.m
FMDatabaseAdditions.h
FMDatabaseAdditions.m
FMDatabasePool.h
FMDatabasePool.m
FMDatabaseQueue.h
FMDatabaseQueue.m
FMResultSet.h
FMResultSet.m

创建数据库

创建数据库只须要以下一行便可,当该文件不存在时,fmdb会本身建立一个。若是你传入的参数是空串:@”” ,则fmdb会在临时文件目录下建立这个数据库,若是你传入的参数是 NULL,则它会创建一个在内存中的数据库。数据库

1
FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];

打开数据库

使用以下语句,若是打开失败,多是权限不足或者资源不足。一般打开完操做操做后,须要调用close方法来关闭数据库。安全

1
2
3
4
5
6
7
8
if (![db open]) {
    // error 
    return;
}
// some operation
// ...

[db close];

执行更新操做

除了Select操做以外,其它的都是更新操做。更新操做使用以下方法,若是有错误,能够用error参数中得到。多线程

1
-[FMDatabase executeUpdate:error:withArgumentsInArray:orVAList:]

执行查询操做

查询操做示例以下。注意:即便操做结果只有一行,也须要先调用FMResultSet的next方法。闭包

1
2
3
4
5
6
7
8
9
FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"];
while ([s next]) {
    //retrieve values for each record
}

FMResultSet *s = [db executeQuery:@"SELECT COUNT(*) FROM myTable"];
if ([s next]) {
    int totalCount = [s intForColumnIndex:0];
}

FMDB提供以下多个方法来获取不一样类型的数据:app

1
2
3
4
5
6
7
8
9
10
11
intForColumn:
longForColumn:
longLongIntForColumn:
boolForColumn:
doubleForColumn:
stringForColumn:
dateForColumn:
dataForColumn:
dataNoCopyForColumn:
UTF8StringForColumnIndex:
objectForColumn:

一般状况下,你并不须要关闭FMResultSet,由于相关的数据库关闭时,FMResultSet也会被自动关闭。oop

数据参数

一般状况下,你能够按照标准的SQL语句,用?表示执行语句的参数,如:spa

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

而后,能够咱们能够调用executeUpdate方法来将?所指代的具体参数传入,一般是用变长参数来传递进去的,以下:

1
2
NSString *sql = @"insert into User (name, password) values (?, ?)";
[db executeUpdate:sql, user.name, user.password];

这里须要注意的是,参数必须是NSObject的子类,因此象int,double,bool这种基本类型,须要封装成对应的包装类才行,以下所示:

1
2
3
4
// 错误,42不能做为参数
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", 42];
// 正确,将42封装成 NSNumber 类
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:42]];

线程安全

若是咱们的app须要多线程操做数据库,那么就须要使用FMDatabaseQueue来保证线程安全了。切记不能在多个线程中共同一个FMDatabase对象而且在多个线程中同时使用,这个类自己不是线程安全的,这样使用会形成数据混乱等问题。

使用FMDatabaseQueue很简单,首先用一个数据库文件地址来初使化FMDatabaseQueue,而后就能够将一个闭包(block)传入inDatabase方法中。在闭包中操做数据库,而不直接参与FMDatabase的管理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 建立,最好放在一个单例的类中
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]) {
        // …
    }
}];

// 若是要支持事务
[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]];
}];
相关文章
相关标签/搜索