iOS之FMDB的基本使用

来源:互联网 发布:网络教育考试时间 编辑:程序博客网 时间:2024/06/05 15:15
  • 优点 :
    • 对多线程的并发操作进行处理,所以是线程安全的
    • 以OC的方式封装了SQLite的C语言API,使用起来更加的方便;
    • FMDB是轻量级的框架,使用灵活
  • 缺点:
    • 因为它是OC的语言封装的,只能在iOS开发的时候使用, 所以在实现跨平台操作的时候存在局限性

FMDB中重要的类

  • FMDatabase : 一个FMDatabase对象就代表一个单独的SQLite数据库, 用来执行SQL语句
  • FMResultSet : 使用FMDatabase执行查询的结果集
  • FMDatabaseQueue : 用于在多线程中执行多个查询或更新,它是线程安全的

FMDB数据库(SQLite)下的使用 :

 注意: 创建FMDatabase对象时参数为SQLite数据库文件路径, 该路径可以是一下三种方式之一- 文件路径.该文件路径无需真是存在,如果不存在会自动创建- 空字符串(@“”).  表示会在临时目录创建一个空的数据库,当FMDatabase连接关闭时,文件也会被删除- NULL.  将创建一个内在数据库, 同样的, 当FMDatabase连接关闭时, 数据将会被摧毁 首先要导入libsqlite3.0框架,导入头文件 import <FMDB/FMDB.h> 代码实现:      (对FMDB中数据库的增删改查的简单封装)
#import "FMDBHelp.h"#import <FMDB/FMDB.h>@interface FMDBHelp ()@property(nonatomic,strong)NSString *fileName;//数据库文件的路径@property(nonatomic,strong)FMDatabase *database; //数据库对象@end@implementation FMDBHelp#pragma mark - 单例+ (FMDBHelp*)sharedFMDBHelp {    static FMDBHelp *help = nil;    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        help = [[FMDBHelp alloc] init];    });    return help;}#pragma mark - 让用户来命名数据库的名称- (void)createDBWithName:(NSString*)dbName {    if (dbName.length == 0) {        //是防止用户直接传值为nil 或者 NULL        self.fileName = @"";    } else {        //判断用户是否为数据库文件添加后缀名        if ([dbName containsString:@".sqlite"]) {            self.fileName = dbName;        } else {            self.fileName = [dbName stringByAppendingString:@".sqlite"];        }    }}#pragma amrk - 根据名称创建沙盒路径用来保存数据库文件- (NSString*)dbPath {    //说明fileName不为空    if (self.fileName.length) {        //获取沙盒主路径        NSString *homePath = NSHomeDirectory();        //完整路径        NSString *savePath = [homePath stringByAppendingPathComponent:[NSString stringWithFormat:@"documents/%@",self.fileName]];        NSLog(@"%@",savePath);        return savePath;    } else {        return @"";    }}#pragma mark - 创建数据库对象//懒加载- (FMDatabase*)database {    if (!_database) {        _database = [FMDatabase databaseWithPath:[self dbPath]];    }    return _database;}#pragma mark - 打开或者创建数据库- (BOOL)openOrCreateDB {    if ([self.database open]) {        NSLog(@"数据库打开成功");        return YES;    } else {        NSLog(@"数据库打开失败");        return NO;    }}#pragma mark - 无返回结果集的操作- (BOOL)notResultSetWithSql:(NSString*)sql {    //打开数据库    BOOL isOpen = [self openOrCreateDB];    if (isOpen) {        //进行操作        BOOL isSuccess = [self.database executeUpdate:sql];        [self closeDB];        NSLog(@"打开数据库成功");        return isSuccess;    } else {        NSLog(@"打开数据库失败");        return NO;    }}#pragma mark - 关闭数据库的方法- (void)closeDB {    BOOL isClose = [self.database close];    if (isClose) {        NSLog(@"关闭数据库成功");    } else {        NSLog(@"关闭数据库失败");    }}#pragma mark - 通用的查询方法- (NSArray*)qureyWithSql:(NSString*)sql {    //打开数据库    BOOL isOpen = [self openOrCreateDB];    if (isOpen) {        //得到所有记录的结果集        FMResultSet *set = [self.database executeQuery:sql];        //声明一个可变数组,用来存放所有的记录        NSMutableArray *array = [NSMutableArray array];        //遍历结果集,取出每一条记录,将每一条记录转换为字典类型,并且存储到可变数组中        while ([set next]) {            //直接将一条记录转换为字典类型            NSDictionary *dic = [set resultDictionary];            [array addObject:dic];        }        //释放结果集        [set close];        [self closeDB];        return array;    } else {        NSLog(@"打开数据库失败");        return nil;    }}
#import <Foundation/Foundation.h>@interface FMDBHelp : NSObject+ (FMDBHelp*)sharedFMDBHelp;//给数据库命名- (void)createDBWithName:(NSString*)dbName;//无返回结果集的操作- (BOOL)notResultSetWithSql:(NSString*)sql;//查询操作- (NSArray*)qureyWithSql:(NSString*)sql;@end

FMDB多线程下的使用

  • 如果应用中使用了多线程操作数据库, 那么就需要使用FMDatabaseQueue来保证线程安全. 应用中不可再多个线程中公共使用一个FMDatabase对象操作数据库,这样会引起数据库数据混乱(例如,使用两个线程同时对数据库进行更新和查找). 为了多线程操作数据库安全, FMDB使用了FMDatabaseQueue.
  • 多个线程更新相同的资源导致数据竞争时使用等待队列(等待现在执行的处理结束)
//    打开数据库    [self openDB];//    在子线程中执行数据库插入操作    dispatch_sync(dispatch_get_global_queue(0, 0), ^{        [self threadNoTransaction];    });#pragma mark - 数据存储文件的路径- (NSString *)dbPath {    NSString *string = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];    NSString *stringPath = [string stringByAppendingPathComponent:@"test.sqlite"];    NSLog(@"%@",stringPath);    return stringPath;}#pragma mark - 打开数据库并建表- (void)openDB {    FMDatabase *database = [FMDatabase databaseWithPath:[self dbPath]];    //打开数据库,如果数据库打开,建表,如果失败就返回错误信息    if([database open]) {        //建表       BOOL isSuccess = [database executeUpdate:@"create table if not exists stu(name text)"];        if (isSuccess) {            NSLog(@"建表成功");        } else {            NSLog(@"建表失败");        }    } else {        NSLog(@"打开数据库失败");    }}#pragma mark - 多线程操作数据库时,非事务的处理方式// 事务(Transaction)是并发控制的基本单位。所谓的事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。例如,银行转账工作:从一个账号扣款并使另一个账号增款,这两个操作要么都执行,要么都不执行。所以,应该把它们看成一个事务。事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性- (void)threadNoTransaction {    //数据库文件的路径    FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:[self dbPath]];    //将一组操作添加到非事务处理中    [queue inDatabase:^(FMDatabase *db) {        //将操作放入事务中,加入事务操作        [db beginTransaction];        BOOL isError = NO;        int temp = -1;        for (int i = 0; i < 10000; i++) {            isError = [db executeUpdate:@"insert into stu values(?)",@(i)];            if (!isError) {//说明inError == NO,插入有问题                if(temp == -1) {                    temp = i;                }            }        }        if (isError) {            NSLog(@"所有插入动作成功");        } else {            NSLog(@"所有插入动作失败---%d",temp);        }        //提交事务        [db commit];    }];}#pragma mark - 多线程操作数据库时,事务的处理方式- (void)threadTransaction {    //创建队列    FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:[self dbPath]];    __block BOOL whoopsSomethingWrongHappened = true;    //把任务包装到事务里    [queue inTransaction:^(FMDatabase *db, BOOL *rollback) {        whoopsSomethingWrongHappened &= [db executeUpdate:@"insert into myTable values(?)",[NSNumber numberWithInt:1]];        whoopsSomethingWrongHappened &= [db executeUpdate:@"insert into myTable values(?)",[NSNumber numberWithInt:2]];        whoopsSomethingWrongHappened &= [db executeUpdate:@"insert into myTable values(?)",[NSNumber numberWithInt:3]];        //如果有错误 返回        if(!whoopsSomethingWrongHappened) {            *rollback = YES;            return;        }    }];}
1 0
原创粉丝点击