zoukankan      html  css  js  c++  java
  • 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】
  • 相关阅读:
    android 自定义dialog 易扩展
    android 圆角item shape
    模板方法模式
    观察者模式
    工厂方法模式(选自《设计模式之禅》)
    单例模式
    如何快速创建静态WEB站点
    React Native 插件系列之lottie-react-native
    JavaJavaScript小问题系列之JSON解析
    React Native 插件系列之PushNotificationIOS
  • 原文地址:https://www.cnblogs.com/xiu619544553/p/5364586.html
Copyright © 2011-2022 走看看