数据存储 FMDB

数据存储 —FMDB

一、FMDB简介

 

iOS中原生的SQLite API在进行数据存储的时候,需要使用C语言中的函数,操作比较繁琐。于是,就出现了一系列将SQLite API进行封装的库,例如FMDB、PlausibleDabase、SQLitePersistentObjects等。

FMDB是一款简洁、易用的封装库。因此,在这里推荐使用第三方框架FMDB,它是对lisqlite3框架的封装,用起来的步骤与SQLite使用类似,并且它对于多线程的并发操作进行了处理,所以是线程安全的。

 

 

FMDB优缺点

 

优点:

1、对多线程的并发操作进行处理,所以是线程安全的;

2、以OC的方式封装了SQLite的C语言API,使用起来更加的方便;

3、FMDB是轻量级的框架,使用灵活。

 

缺点:

1、因为它是OC的语言封装的,只能在iOS开发的时候使用,所以在实现跨平台操作的时候存在局限性。

 

 

FMDatabase:一个FMDatabase对象就代表一个单独的SQLite数据库,用来执行SQL语句。

 

FMResultSet:使用FMDatabase执行查询后的结果集。

 

FMDatabaseQueue:用于在多线程中执行多个查询或更新,它是线程安全的。

 

FMDB使用步骤

 

1.下载FMDB文件(gitHub链接:https://github.com/ccgus/fmdb),并将FMDB文件夹添加到项目中(也可以使用CocoaPods导入)

2.导入lisqlite3.0框架,导入头文件FMDatabase.h

 

3.代码实现,与SQLite使用步骤相似,创建数据库路径没货的数据库路径,打开数据库,然后对数据库进行增、删、改、查操作,最后关闭数据库。

 

二、FMDB创建数据库和数据表

 

创建FMDatabsae对象时参数为SQLite数据库文件路径,该路径可以是以下三种方式之一

1、文件路径。该文件路径无需真是存在,如果不存在会自动创建

2.空字符串(@“”)。表示会在临时目录创建一个空的数据库,当FMDatabase连接关闭时,文件也会被删除;

3.NULL。将创建一个内咋数据库,同样的,当FMDatabase连接关闭时,数据将会被销毁

 

FMDB—数据库创建

建立数据库

 

//1.获得数据库文件的路径

 

NSString *doc = [NSSEarchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)LastObject];

NSString *fileName = [doc stringByAppendingPathComponent:@“student.sqlite”];

 

//2.获得数据库

 

FMDatabase *db = [FMDatabase databaseWithPath:fieName];

 

//3.在和数据库交互之前,数据库必须是打开的,如果权限不足或者资源不足,则无法打开和创建数据库。

 

if([db open] ){

 

//创建表

 

}

//4.创建表

 

 

if([db open]) {

BOOL result = [db executeUpdate:@“CREATE TABLE IF NOT EXISTS t_student (id integer PRIMARY KEY AUTOINCREMENT ,name text NOT NULL,age integer NOT NULL);”];

 

if (result) {

NSL(@“创建表成功”);

 

  }

 

关闭数据库

[db close];

}

 

 

 

三、FMDB实现增、删、改、查

 

 

FMDB - 执行更新

 

一切不是SELECT命令的命令都视为更新。这包括CREAT,UPDATE,INSERT,ALTER,BEGIN,COMMIT,DETACH,DELETE,DROP,END,EXPLAI,VACUUM,REPLACE等。

 

 

简单来说,只有不是以SELECT开头的命令都是更新命令。

 

执行更新返回一个BOOL值。YES表示执行成功,否则表示有错误。你可以调用-lastErrorMessage和-lastErrorCode方法来得到更多信息。

 

 

int age = 42;

 

//1.executeUpdate:不确定的参数用?来占位(后面参数必须是oc对象。:代表语句结束)

 

[self.db executeUpdate:@“INSERT INTO t_student(name,age)VALUES(?,?),name,@(age)”];

 

 

//2.executeUpdateWithFormat:不确定的参数用%@,%d等来占位(参数为原始数据类型,执行语句不区分大小写)

 

[self.db executeUpdateithFormat:@“insert into t_student(name,age)values(%@,%i);”,name,age];

 

//3.数组

 

[self.db executeUpdate:@“INSERT INTO  t_student(name,age)VALUES(?,?);” withArgumentInarray:@[name,@(age)]];

 

 

FMDB —删除数据

 

 

//1.不确定的参数用?来占位(后面参数必须是oc对象)

 

[self.db executeUpdate:@“delete from t_student where id = ?;”,@(idNum)];

 

 

//2.不确定的参数用%@,%d等来占位

 

[self.db executeUpdateWithFormat:@“delete from t——student where 那么= %@;“,@”apple_name“];

 

//如果表格存在 则销毁

 

[self.db execyteUpdate:@“drop table if exists t_student;”];

 

 

FMDB—修改数据

 

//修改学生的名字

 

[self.db executeUpdate:@“update t_student set name = ? where name = ?”,newName,oldName];

 

 

FMDB—查询数据

 

1、SELECT命令就是查询,执行查询的方法是以ececuteQuery开头的。

2、执行查询时,如果成功返回FMResultSet对象,错误返回nil。与指向更新相同,支持使用NSError参数。

3、同时,你也可以使用-lasErrorCode和-lastErrorMessage获知错误信息

 

 

intForColumn

 

longForColumn

 

longLongIntForColumn

 

boolForColumn

 

doubleForColumn

 

stringForColumn

 

dataForColumn

 

dataNoCopyForColumnIndex

 

UTF8StringForColumnIndex

 

objectForColumn

 

 

 

FMDB—查询数据

 

//1.执行查询语句

 

//查询整个表

 

FMResult *result = [self.db executeQuery:@”select *from t_student;“];

 

//根据条件查询

 

FMResultSet *resultSet = [self.db executeQuery:@“select *from t_student where id<?;”,@(14)];

 

//遍历结果集合

 

while ([resultSet next]) {

int idNum = [resultSet intForColumn:@“id”];

 

NSString *name = [resultSet objectForColumn:@“name”];

 

int age = [resultSet intForColumn:@“age”];

 

}

 

四、FMDB实现多线程操作

 

 

FMDB - 多线程下的使用

 

FMDatabase实例能否在多线程中使用

 

如果应用中使用了多线程操作数据库,那么久需要使用FMDatabaseQueue来保证线程安全了。应用中不可再多个线程中共同使用一个FMDatabase对象作数据库,这样会引起数据库数据混乱(例如使用两个线程同时对数据库进行更新和查找)。为了多线程操作数据库安全,FMDB使用了FMDatabaseQueue。

 

多线程更新相同的资源导致数据竞争会死使用等待队列(等待现在执行的处理结束).

 

 

//1.创建队列

 

FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];

 

__block BOOl whoopsSomethingWrongHappened = true;

 

 

//2.把任务包装到事务里

 [queue inTransaction:^(FMDatabase *db, BOOL *rollback) {

       

        //串行队列

        

        isSucceed = [db executeUpdate:@"insert into t_student(name,age,sex) values (?,?,?)",@"GBLW",@"38",@"男"] && isSucceed;

        

        isSucceed = [db executeUpdate:@"insert into t_student(name,age,sex)values(?,?,?)",@"-1",@"438",@"未知"] && isSucceed;

        

        isSucceed = [db executeUpdate:@"insert into t_student(name,age,sex)values(?,?,?)",@"AJAR",@"18",@"男"] && isSucceed;

        

        //如果有错误,就会将它返回

        if (!isSucceed) {

            //block返回的参数rollback进行处理(bool类型的指针)

            

            *rollback = YES;

            return ;

        }

        

    }];

    

    //关闭数据库

    [self.dataBase close];

}

//布局button

#import "ViewController.h"

//第一步:引入框架,引入支持类库(libsqlite3.0tbd)

#import <FMDB.h>

@interface ViewController ()
///声明数据库对象
@property(nonatomic,strong)FMDatabase *dataBase;
///声明存储路径
@property(nonatomic,copy)NSString *filePath;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    //创建表
    [self creatTable];
    unsigned char  i = 0;   i = ~i;
    
    NSLog(@"i=%c",i);
}
#pragma mark - 创建表


- (void)creatTable {
    //第一步:创建sql语句
    NSString *createSql = @"create table if not exists t_student(id integer primary key autoincrement not null ,name text not null,age integer not null,sex text not null)";
    
    //第二步:找到存储路径
    
    
    NSString *document = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
    
    NSLog(@"document = %@",document);
    
    self.filePath  = [document stringByAppendingPathComponent:@"student.sqlite"];
    
    NSLog(@"filePath = %@",self.filePath);
    
    //第三步:使用路径初始化DMDB对象
    
    self.dataBase = [FMDatabase databaseWithPath:self.filePath];
    //第四步:数据库执行相关的操作
    //需要判断数据库打开的时候才进行执行语句
    if ([self.dataBase open]) {
        BOOL result = [self.dataBase executeUpdate:createSql];
        if (result) {
            NSLog(@"创建表成功");
        }else {
            NSLog(@"创建表失败");
        }
    }
    
    //第五步:关闭数据库
    [self.dataBase close];
}
#pragma mark - 添加学生
- (IBAction)insertIntoAction:(id)sender {
    
    //第一步:打开数据库
    [self.dataBase open];
    
    //第二步:进行相关的操作
    
    NSArray * nameArr = [NSArray arrayWithObjects:@"MBBoy",@"炸天",@"小明", nil];
    for (int i = 0; i < nameArr.count; i++) {
      
        NSString *name = [nameArr objectAtIndex:i];
        
         //插入语句
//        NSString *insertSql = @"insert into t_student(name,age,sex) values(?,?,?)";
        
   BOOL result = [self.dataBase executeUpdate:@"insert into t_student(name,age,sex) values(?,?,?)",name,@"69",@"男"];
        
        if (result) {
            NSLog(@"插入成功");
        }else {
            NSLog(@"插入失败");
            NSLog(@"result = %d",result);
        }
    }
    //关闭数据库
    [self.dataBase close];
}
#pragma MARK - 更改学生
- (IBAction)updeAction:(id)sender {
    
    //打开数据库
    [self.dataBase open];
    BOOL result = [self.dataBase executeUpdate:@"update t_student set name = ? where name = ?",@"孟令旭",@"MBBoy"];
    
    if (result) {
        NSLog(@"更改成功");
    }else {
        NSLog(@"更改失败");
    }
    [self.dataBase close];
}
#pragma mark - 删除学生

- (IBAction)deleteAction:(id)sender {
    
    //打开数据库
    [self.dataBase open];
    //执行sql语句
    
    BOOL result = [self.dataBase executeUpdate:@"delete from t_student where name = ?",@"孟令旭"];
    
    if (result) {
        NSLog(@"删除成功");
    }else {
        NSLog(@"删除失败");
    }
    
    //关闭数据库
    [self.dataBase close];
    
}
#pragma mak - 查询学生
- (IBAction)searchAction:(id)sender {
    
    //查询表中的所有数据
    [self.dataBase open];
    
    //查询结果使用的类FMResultSet
    
    FMResultSet *resultSet = [self.dataBase executeQuery:@"select * from t_student"];
    
    //遍历出需要的结果内容
    
    while ([resultSet next]) {
        NSString * name = [resultSet objectForColumnName:@"name"];
        NSInteger age = [resultSet intForColumn:@"age"];
        NSString *sex = [resultSet objectForColumnName:@"sex"];
        NSLog(@"name = %@,age = %ld,sex = %@",name,age,sex);
                   
    }
    //关闭数据库
    [self.dataBase close];
}

#pragma mark - 插入很多学生
- (IBAction)insertManyStudents:(id)sender {
    
    //以队列的形式添加数据是FMDB比较常用的添加方式
    
    //FMDB不支持多个线程同时操作,所以一般以串行的方式实现相关的操作
    //第一步:创建操作队列
    //打开数据库
    [self.dataBase open];
    FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:self.filePath];
    
    //标识:记录是否操作成功
    
    __block BOOL isSucceed = YES;
    
    //第二步:把所需要的事件打包放在操作队列中
    
    [queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
       
        //串行队列
        
        isSucceed = [db executeUpdate:@"insert into t_student(name,age,sex) values (?,?,?)",@"GBLW",@"38",@"男"] && isSucceed;
        
        isSucceed = [db executeUpdate:@"insert into t_student(name,age,sex)values(?,?,?)",@"-1",@"438",@"未知"] && isSucceed;
        
        isSucceed = [db executeUpdate:@"insert into t_student(name,age,sex)values(?,?,?)",@"AJAR",@"18",@"男"] && isSucceed;
        
        //如果有错误,就会将它返回
        if (!isSucceed) {
            //block返回的参数rollback进行处理(bool类型的指针)
            
            *rollback = YES;
            return ;
        }
        
    }];
    
    //关闭数据库
    [self.dataBase close];
}



@end

  

 

posted @ 2016-05-30 17:23  维他命11  阅读(351)  评论(0编辑  收藏  举报