zoukankan      html  css  js  c++  java
  • 数据存储 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
    

      

     

  • 相关阅读:
    浅谈LBS(基于位置的服务)
    MapBar地图更新啦
    推荐一款软件:Global Mapper
    51ditu、清华地图以及Google地图
    极索(Gsuo)推出新版地图采用Gmap设计思路
    公告:Rover's Official Blog停止更新
    最后的礼物:校园多媒体系统和校园WEBGIS系统
    JAVA中最常用的十个快捷键
    启程去旅行 android之merge布局 http://www.cnblogs.com/travelfromandroid/articles/2133206.html
    Http 范例
  • 原文地址:https://www.cnblogs.com/mingjieLove00/p/5543231.html
Copyright © 2011-2022 走看看