FMDB简单使用

概念

FMDB 是 iOS 平台的 SQLite 数据库框架; FMDB 以 OC 的方式封装了 SQLite 的 C 语言 API。以面相对象的方式操作数据库。
 

FMDB的优点

1) 使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码;
2) 对比苹果自带的 Core Data 框架,更加轻量级和灵活;
3) 提供了多线程安全的数据库操作方法,有效地防止数据混乱;
 

API讲解:

FMDB的三个主要类别:

  • FMDatabase ——代表一个 SQLite 数据库。 用于执行 SQL 语句。
  • FMResultSet ——执行查询一个 FMDatabase 的结果集
  • FMDatabaseQueue ——在多线程操作更新和查询时,需要使用这个类,它是线程安全的。

 

非线程安全数据库创建方法:

/**
 *  @brief 创建一个数据库对象
     数据库被创建时,数据库文件路径有三种情况:
     1)具体文件路径 : 如果不存在会自动创建;
     2)空字符串@"" : 会在临时目录创建一个空的数据库,当FMDatabase连接关闭时,数据库文件也被删除;
     3)nil : 会创建一个内存中临时数据库,当FMDatabase连接关闭时,数据库会被销毁;
 *
 *  @param inPath 数据库路径(绝对路径)
 *
 *  @return 返回对象结果
 */
+ (instancetype)databaseWithPath:(NSString*)inPath;

 

/**
 *  @brief 打开数据库
 *
 *  @return YES,成功;NO,失败
 */
- (BOOL)open;

 

/**
 *  @brief FMDB 中该方法相当于 `CREATE`,`UPDATE`,`INSERT`,`DELETE`(增删改)
 *
 *  @param sql 指定执行的 SQL 语句
 *
 *  @return YES,执行成功;NO,失败
 */
- (BOOL)executeUpdate:(NSString*)sql, ...;

 

 

线程安全数据库创建:

/**
 *  @brief 创建数据库实例(查看源码可知:调用该方法后,数据库已打开)
 *
 *  @param aPath 数据库绝对路径
 *
 *  @return 返回数据对线程对象
 */
+ (instancetype)databaseQueueWithPath:(NSString*)aPath;

/**
 *  @brief 同步队列执行数据库操作(dispatch_sync实现,该方法线程安全)
 *
 *  @param block 回调数据库本身,我们可以在代码块内操作数据库
 */
- (void)inDatabase:(void (^)(FMDatabase *db))block;

 

代码

非线程安全代码:

///=============================================================================
/// @name 非线程安全数据库
///=============================================================================
#pragma mark - 创建非线程安全的数据库
- (void)createNonatomicDBWithDbPath:(NSString *)dbPath {
    // 创建数据库的实例
    self.db = [FMDatabase databaseWithPath:dbPath];
    
    // 打开数据库
    BOOL flag = [self.db open];
    if (flag) {
        DLog(@"db open success.");
    } else {
        DLog(@"db open failed.");
    }
    
    // 创建表
    BOOL exeFlag = [self.db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_kingdev (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, phone TEXT NOT NULL, height REAL NOT NULL)"];
    if (exeFlag) {
        DLog(@"CREATE success");
    } else {
        DLog(@"CREATE failed");
    }
}

//
- (IBAction)insertInto:(id)sender {
    BOOL flag = [self.db executeUpdate:@"INSERT INTO t_kingdev (name, phone, height) VALUES (?, ?, ?)", [NSString stringWithFormat:@"张%d", arc4random_uniform(50)], [NSString stringWithFormat:@"%d", arc4random_uniform(20)], [NSNumber numberWithFloat:(arc4random_uniform(1000) / 10.f)]];
    if (flag) {
        DLog(@"INSERT INTO success");
    } else {
        DLog(@"INSERT INTO failed");
    }
}

//
- (IBAction)delete:(id)sender {
    // 删除  id 大于 20 的数据库数据
    BOOL flag = [self.db executeUpdate:@"DELETE FROM t_kingdev WHERE id > 20"];
    if (flag) {
        DLog(@"DELETE success");
    } else {
        DLog(@"DELETE failed");
    }
}

//
- (IBAction)update:(id)sender {
    // '张三' ——> 改为 'Flora'
    [self.db executeQuery:@"update t_kingdev set name = 'Flora' where name = '张三';"];
}

//
- (IBAction)select:(id)sender {
    FMResultSet *resultSet = [self.db executeQuery:@"select * from t_kingdev"];
    // 从结果集往下找
    while ([resultSet next]) {
        // 根据字段取值
        NSString *name = [resultSet stringForColumn:@"name"];
        NSString *phone = [resultSet stringForColumn:@"phone"];
        double height = [resultSet doubleForColumn:@"height"];
        DLog(@"name=%@ phone=%@ height=%f", name, phone, height);
    }
}

 

 

线程安全数据库和事务代码:
///=============================================================================
/// @name 数据库多线程安全和事务
///=============================================================================
/** 
 模拟场景:
 甲:500元
 乙:1000元
 乙给甲转账500元。
 */
#pragma mark - 创建线程安全的数据库
- (void)createAtomicDB {
    NSString *docDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSString *dbPath = [docDir stringByAppendingPathComponent:@"t_bank.sqlite"];
    // 创建队列且默认开发了数据库
    FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
    [queue inDatabase:^(FMDatabase *db) {
        // code····Operate db
        BOOL flag = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_bank (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, money INTEGER NOT NULL)"];
        if (flag) {
            DLog(@"create t_bank success");
        } else {
            DLog(@"create t_bank failed");
        }
    }];
    _queue = queue;
}

//
- (IBAction)at_Add:(id)sender {
    [_queue inDatabase:^(FMDatabase *db) {
        BOOL flag = [db executeUpdate:@"INSERT INTO t_bank (name, money) VALUES (?, ?);", @"", @500];
        [db executeUpdate:@"INSERT INTO t_bank (name, money) VALUES (?, ?);", @"", @1000];
        if (flag) {
            DLog(@"INSERT INTO t_bank success");
        } else {
            DLog(@"INSERT INTO t_bank failed");
        }
    }];
}

//
- (IBAction)at_delete:(id)sender {
    [_queue inDatabase:^(FMDatabase *db) {
        BOOL flag = [db executeUpdate:@"DELETE FROM t_bank"];
        if (flag) {
            DLog(@"DELETE t_bank success");
        } else {
            DLog(@"DELETE t_bank failed");
        }
    }];
}

/** 
 
 操作1:乙 (1000 - 500) 扣500
 操作2:甲 (500 + 500)  得500
 
 操作1和操作2必须一起成功,称为一个不可分割的工作单元。所以我们用到了事务
 
 若事务内的操作失败了某个,则数据库回滚到事务之前的状态!!
 
 */
//
- (IBAction)at_update:(id)sender {
    [_queue inDatabase:^(FMDatabase *db) {
        
        // 开启事务
        [db beginTransaction];
        
        // 操作1
        BOOL flag1 = [db executeUpdate:@"UPDATE t_bank SET money = 500 WHERE name = '乙';"];
        if (flag1) {
            DLog(@"flag1UPDATE t_bank success");
        } else {
            DLog(@"flag1UPDATE t_bank failed");
            
            // 失败回滚
            [db rollback];
        }
        
        // 操作2
        BOOL flag2 = [db executeUpdate:@"UPDATE t_bank SET money = 1000 WHERE name = '甲';"];
        if (flag2) {
            DLog(@"flag2UPDATE t_bank success");
        } else {
            DLog(@"flag2UPDATE t_bank failed");
            
            // 失败回滚
            [db rollback];
        }
        
        // 提交事务
        [db commit];
    }];
}

//
- (IBAction)at_slect:(id)sender {
    [_queue inDatabase:^(FMDatabase *db) {
        FMResultSet *rs = [db executeQuery:@"SELECT * FROM t_bank"];
        while ([rs next]) {
            DLog(@"name = %@  money = %d", [rs stringForColumn:@"name"], [rs intForColumn:@"money"]);
        }
    }];
}

 

参考:
 
尊重作者劳动成果,转载请注明: 【kingdev】
posted @ 2016-04-11 15:26  Kingdev  阅读(329)  评论(0编辑  收藏  举报