ios FMDB

一. 什么是FMDB ?

iOS中使用C语言函数对原生SQLite数据库进行增删改查操作,复杂麻烦,于是,就出现了一系列将SQLite API封装的库,如FMDB
FMDB是针对libsqlite3框架进行封装的三方,它以OC的方式封装了SQLite的C语言的API,使用步骤与SQLite相似
FMDB的优点是:
(1) 使用时面向对象,避免了复杂的C语言代码
(2) 对比苹果自带的Core Data框架,更加轻量级和灵活
(3) 提供多线程安全处理数据库操作方法,保证多线程安全跟数据准确性
FMDB缺点:
(1) 因为是OC语言开发,只能在iOS平台上使用,所以实现跨平台操作时存在限制性
FMDB 在Git上的下载链接地址: https://github.com/ccgus/fmdb
二. 主要类型
FMDatabase:一个FMDatabase对象代表一个单独的SQLite数据库,通过SQLite语句执行数据库的增删改查操作
FMResultSet:使用FMDatabase对象查询数据库后的结果集
FMDatabaseQueue:用于多线程操作数据库,它保证线程安全-----官方建议使用这个,线程安全的


三:部分demo数据
/*
*  FMDatabaseQueue使用案例
*/
- (void)FMDatabaseQueueTest{
    //1、获取数据库文件路径
    NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *fileName = [doc stringByAppendingPathComponent:@"students.sqlite"];
    
    //使用
    FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:fileName];
    [queue inDatabase:^(FMDatabase *db) {  
        [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_student_2 (id integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL, age integer NOT NULL);"];
        [db executeUpdate:@"INSERT INTO t_student_2 (name, age) VALUES ('yixiangZZ', 20);"];
        [db executeUpdate:@"INSERT INTO t_student_2 (name, age) VALUES ('yixiangXX', 25);"];
        
        FMResultSet *rs = [db executeQuery:@"SELECT * FROM t_student_2"];
        
        NSLog(@"%@",[NSThread currentThread]);
        while ([rs next]) {
            int ID = [rs intForColumn:@"id"];
            NSString *name = [rs stringForColumn:@"name"];
            int age = [rs intForColumn:@"age"];
            NSLog(@"%d %@ %d",ID,name,age);
        }
        
    }];
    
    //支持事务
    [queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
        [db executeUpdate:@"UPDATE t_student_2 SET age = 40 WHERE name = 'yixiangZZ'"];
        [db executeUpdate:@"UPDATE t_student_2 SET age = 45 WHERE name = 'yixiangXX'"];
        
        BOOL hasProblem = NO;
        if (hasProblem) {
            *rollback = YES;//回滚
            return;
        }
        
        FMResultSet *rs = [db executeQuery:@"SELECT * FROM t_student_2"];
        NSLog(@"%@",[NSThread currentThread]);
        while ([rs next]) {
            int ID = [rs intForColumn:@"id"];
            NSString *name = [rs stringForColumn:@"name"];
            int age = [rs intForColumn:@"age"];
            NSLog(@"%d %@ %d",ID,name,age);
        }
        
    }];
}

/**
 *  FMDatabaseQueue如何实现多线程的案例
 */
- (void)FMDatabaseQueueMutilThreadTest{
    //1、获取数据库文件路径
    NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *fileName = [doc stringByAppendingPathComponent:@"students.sqlite"];
    
    //使用queue1
    FMDatabaseQueue *queue1 = [FMDatabaseQueue databaseQueueWithPath:fileName];
    
    [queue1 inDatabase:^(FMDatabase *db) {
        for (int i=0; i<10; i++) {
            NSLog(@"queue1---%zi--%@",i,[NSThread currentThread]);
        }
    }];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [queue1 inDatabase:^(FMDatabase *db) {
            for (int i=11; i<20; i++) {
                NSLog(@"queue1---%zi--%@",i,[NSThread currentThread]);
            }
        }];
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [queue1 inDatabase:^(FMDatabase *db) {
            for (int i=20; i<30; i++) {
                NSLog(@"queue1---%zi--%@",i,[NSThread currentThread]);
            }
        }];
    });
    
    //虽然开启了多个线程,可依然还是串行处理。原因如下:
    
    /**FMDatabaseQueue虽然看似一个队列,实际上它本身并不是,它通过内部创建一个Serial的dispatch_queue_t来处理通过inDatabase和inTransaction传入的Blocks,所以当我们在主线程(或者后台)调用inDatabase或者inTransaction时,代码实际上是同步的。FMDatabaseQueue这么设计的目的是让我们避免发生并发访问数据库的问题,因为对数据库的访问可能是随机的(在任何时候)、不同线程间(不同的网络回调等)的请求。内置一个Serial队列后,FMDatabaseQueue就变成线程安全了,所有的数据库访问都是同步执行,而且这比使用@synchronized或NSLock要高效得多。
     */
}
相关文章
相关标签/搜索