iOS开发之FMDB

  sqlite作为一个轻量级的数据库,由于它占用的内存很少,因此在很多的嵌入式设备中得到广泛的使用。iOS的SDK很早就开始支持了SQLite,我们只需要加入 libsqlite3.dylib 以及引入 sqlite3.h 头文件即可,但由于原生sqlite的API不是很友好,因此使用的话一般会对其做一层封装,其中以开源的FMDB最为流行。

FMDB主要的类

1.FMDatabase – 表示一个单独的SQLite数据库。 用来执行SQLite的命令。

2.FMResultSet – 表示FMDatabase执行查询后结果集

3.FMDatabaseQueue – 当你在多线程中执行操作,使用该类能确保线程安全。

 

FMDB的使用

数据库的创建

创建FMDatabase对象时需要参数为SQLite数据库文件路径。该路径可以是以下三种之一:

1..文件路径。该文件路径无需真实存,如果不存在会自动创建。

2..空字符串(@”")。表示会在临时目录创建一个临时数据库,当FMDatabase 链接关闭时,文件也被删除。

3.NULL. 将创建一个内存数据库。同样的,当FMDatabase连接关闭时,数据会被销毁。

内存数据库:

  通常数据库是存放在磁盘当中的。然而我们也可以让存放在内存当中的数据库,内存数据库的优点是对其操作的速度较快,毕竟访问内存的耗时低于访问磁盘,但内存数据库有如下缺陷:由于内存数据库没有被持久化,当该数据库被关闭后就会立刻消失,断电或程序崩溃都会导致数据丢失;不支持读写互斥处理,需要自己手动添加锁;无法被别的进程访问。

临时数据库:

  临时数据库和内存数据库非常相似,两个数据库连接创建的临时数据库也是各自独立的,在连接关闭后,临时数据库将自动消失,其底层文件也将被自动删除。尽管磁盘文件被创建用于存储临时数据库中的数据信息,但是实际上临时数据库也会和内存数据库一样通常驻留在内存中,唯一不同的是,当临时数据库中数据量过大时,SQLite为了保证有更多的内存可用于其它操作,因此会将临时数据库中的部分数据写到磁盘文件中,而内存数据库则始终会将数据存放在内存中。

 

创建数据库:FMDatabase *db= [FMDatabase databaseWithPath:dbPath] ;

在进行数据库的操作之前,必须要先把数据库打开,如果资源或权限不足无法打开或创建数据库,都会导致打开失败。

如下为创建和打开数据库的示例:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];

//dbPath: 数据库路径,存放在Document中。
NSString *dbPath = [documentDirectory stringByAppendingPathComponent:@"MYTest.db"];

//创建数据库实例 db  这里说明下:如果路径中不存在"MYTest.db"的文件,sqlite会自动创建"MYTest.db"
FMDatabase *db= [FMDatabase databaseWithPath:dbPath] ;
if (![db open]) {
NSLog(@"Could not open db.");
return ;
}

 

更新操作

一切不是SELECT命令都视为更新操作,包括CREATE, UPDATE, INSERT,ALTER,COMMIT, BEGIN, DETACH, DELETE, DROP, END, EXPLAIN, VACUUM和REPLACE等。

 创建表:

[db executeUpdate:@"CREATE TABLE myTable (Name text,Age integer)"];

插入

[db executeUpdate:@"INSERT INTO myTable (Name,Age) VALUES (?,?)",@"jason",[NSNumber numberWithInt:20]];

更新

[db executeUpdate:@"UPDATE myTable SET Name = ? WHERE Name = ? ",@"john",@"jason"];.

删除

[db executeUpdate:@"DELETE FROM myTable WHERE Name = ?",@"jason"];

查询操作

SELECT命令就是查询,执行查询的方法是以 -excuteQuery开头的。执行查询时,如果成功返回FMResultSet对象, 错误返回nil. 读取信息的时候需要用while循环:

FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"];   
while ([s next]) {   
    //从每条记录中提取信息

}   

 

关闭数据库

当使用完数据库,你应该 -close 来关闭数据库连接来释放SQLite使用的资源。

 [db close];  

参数

通常情况下,你可以按照标准的SQL语句,用?表示执行语句的参数,如:

INSERT INTO myTable VALUES (?, ?, ?)

然后,可以我们可以调用executeUpdate方法来将?所指代的具体参数传入,通常是用变长参数来传递进去的,如下:

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

这里需要注意的是,参数必须是NSObject的子类,所以象int,double,bool这种基本类型,需要进行相应的封装

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

 

多线程操作

  由于FMDatabase对象本身不是线程安全的,因此为了避免在多线程操作的时候出错,需要使用 FMDatabaseQueue来执行相关操作。只需要利用一个数据库文件地址来初使化FMDatabaseQueue,然后传入一个block到inDatabase中,即使是多个线程同时操作,该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]];      
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 (somethingWrongHappened) {
         *rollback = YES;
return; } // etc… [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]]; }];

 

posted @ 2014-10-16 12:32  hello_LJ  阅读(1182)  评论(0编辑  收藏  举报