zoukankan      html  css  js  c++  java
  • 在iOS开发中使用FMDB

    前言

    SQLite (http://www.sqlite.org/docs.html) 是一个轻量级的关系数据库。iOS SDK很早就支持了SQLite,在使用时,只需要加入 libsqlite3.dylib 依赖以及引入 sqlite3.h 头文件即可。但是,原生的SQLite API在使用上相当不友好,在使用时,非常不便。于是,开源社区中就出现了一系列将SQLite API进行封装的库,而FMDB (https://github.com/ccgus/fmdb) 则是开源社区中的优秀者。

    FMDB在使用上相当方便。以下是一个简单的例子:

    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工程,会自动根据工程配置来调整相关的内存管理代码。

    使用说明

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

    引入相关文件

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

    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提供如下多个方法来获取不同类型的数据:

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

    通常情况下,你并不需要关闭FMResultSet,因为相关的数据库关闭时,FMResultSet也会被自动关闭。

    数据参数

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

    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
    
  • 相关阅读:
    [你必须知道的.NET]第二十一回:认识全面的null
    《你必须知道的.NET》,内容简介
    [IT史记]开篇:盖茨本纪之离歌
    《你必须知道的.NET》,封面
    《博客园精华集》,CLR/C#分册征求意见稿
    [开发故事]第二回:LINQ来了,先忘记foreach
    《你必须知道的.NET》,封底
    [不得不转载]一个时代的结束:微软盖茨的人生掠影
    [技术速递]MSDN在线改版,新风格新体验
    《你必须知道的.NET》,勘误支持
  • 原文地址:https://www.cnblogs.com/suenihy/p/3525735.html
Copyright © 2011-2022 走看看