• 第三方框架FMDB


    摘要:关键点:创建、插入、查询、数据格式化
    第三方框架FMDB
    ------------------------------------------------------------------------------------------------------------
    开源
    1)什么是FMDB 
    FMDB是iOS平台的SQLite数据库框架,FMDB以OC的方式封装了SQLite的C语言API。
    2)FMDB的优点 
    a、使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码 
    b、对比苹果自带的Core Data框架,更加轻量级和灵活 
    c、提供了多线程安全的数据库操作方法,有效地防止数据混乱
    ---------------------------------------------------------------------------------
    最主要的类
    FMDatabase:对象代表数据库,主要功能执行SQL语句
    FMResultSet:对象代表查询结果,主要用于保存和处理select语句的查询结果,主要用于保存和处理SELECT语句的查询结果
    注意:
    1、FMDB将所有建表、插入、更新、删除的操作都叫Update,执行这些SQL语句的方法都是
    executeUpdate、executeUpdateWithFormat:
     
     
    2、查询:
    只有执行SELECT语句的方法叫executeQuery:
        给SQL语句传参数:
         ?  :都是对象表示为其他参数,NSString,NSArray, NSDictionary,va_list
         Format:支持各种基本数据类型
    处理查询结果FMResultSet:用于存储executeQuery查询出来的结果
         数据集 next:一次取一次记录
                   每条记录独有几个字段,取字段XXXForColumn,XXX代表字段的类型
    FMResultSet  提供了很多方法来获得所需的格式的值:
        intForColumn:
        longForColumn:
        longLongIntForColumn:
        boolForColumn:
        doubleForColumn:
        stringForColumn:
        dataForColumn:
        dataNoCopyForColumn:
        UTF8StringForColumnIndex:
        objectForColumn:
    这些方法也都包括 {type}ForColumnIndex 的这样子的方法,参数是查询结果集的列的索引位置。
    你无需调用  [FMResultSet close]来关闭结果集, 当新的结果集产生,或者其数据库关闭时,会自动关闭。
     
    数据格式化
    支持的格式:
     
    自动识别对象:?
    字符串:%@, %c, %s
    数值:%d, %D,%i,%u,%U,%ld, %lu,%lld, %llu ,%f
    %hi, %hu, %qi, %qu,
    %g
     
    你需要在SQL语句中使用 % 字符,你应该使用 %%
     
    除此之外的修饰符可能导致无法预知的结果
     
    executeUpdate:?,SQLite风格
    execute*WithFormat: 这是NSString风格的参数
     
    使用FMDB,插入数据前,你不要花时间审查你的数据。你可以使用标准的SQLite数据绑定语法。
    INSERT INTO myTable VALUES (?, ?, ?)
    SQLite会识别 “?” 为一个输入的点位符, 这样的执行会接受一个可变参数(或者表示为其他参数,如NSArray, NSDictionary,va_list等),会正确为您转义。
    你也可以选择使用命名参数语法。
    INSERT INTO myTable VALUES (:id, :name, :value)
    参数名必须以冒名开头。SQLite本身支持其他字符,当Dictionary key的内部实现是冒号开头。注意你的NSDictionary key不要包含冒号。
    NSDictionary *argsDict = [NSDictionary dictionaryWithObjectsAndKeys:@"My Name"@"name"nil];
    [db executeUpdate:@"INSERT INTO myTable (name) VALUES (:name)" withParameterDictionary:argsDict];
    而且,代码不能这么写(为什么?想想吧。答:因为字典提供的参数值不够)
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)"@"this has " lots of ' bizarre " quotes '"];
    你应该:
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)"@"this has " lots of ' bizarre " quotes '"];
     
     提供给 -executeUpdate: 方法的参数都必须是对象
    就像以下的代码就无法工作,且会产生崩溃。
     [db executeUpdate:@"INSERT INTO myTable VALUES (?)"42];
     正确有做法是把数字打包成 NSNumber对象
     [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:42]];
     或者,你可以使用  -execute*WithFormat: ,这是NSString风格的参数
     [db executeUpdateWithFormat:@"INSERT INTO myTable VALUES (%d)"42];
     -execute*WithFormat:  的方法的内部实现会帮你封装数据, 以下这些修饰符都可以使用: %@, %c, %s, %d, %D,%i, %u, %U, %hi, %hu, %qi, %qu, %f, %g, %ld, %lu, %lld, and %llu.  除此之外的修饰符可能导致无法预知的结果。 一些情况下,你需要在SQL语句中使用 % 字符,你应该使用 %%。
     
    //————————————-------------------—create—创建表------------------------------------------
    @property (strongnonatomic)FMDatabase *fmdb;
    NSString *dbFilePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectoryNSUserDomainMaskYES)firstObject]stringByAppendingPathComponent:@"demo3.db"];
    //此对象代表数据库
    self.fmdb = [FMDatabase databaseWithPath:dbFilePath];
    //1. 打开数据库
    if([self.fmdb open]){
        //2. 执行建表SQL
        BOOL res = [self.fmdb executeUpdate:@"CREATE TABLE IF NOT EXISTS emp(id integer PRIMARY KEY, name varchar(20) NOT NULL, age integer, salary double)"];
        if(res){
            NSLog(@"建表成功");
        }else{
            NSLog(@"建表失败:%@", [self.fmdb lastError]);
        }
    }
    [self.fmdb close];
    //—————————------------—————insert into-插入数据------------------------------------------
    1、插入数据:executeUpdateWithFormat
    [self.fmdb open];
    BOOL res = [self.fmdb executeUpdateWithFormat:@"INSERT INTO emp (name, age, salary) VALUES (%@, %d, %f)"self.nameTF.textself.ageTF.text.intValueself.salaryTF.text.doubleValue];
    if(!res){
        NSLog(@"插入数据失败:%@", [self.fmdb lastError]);
    }
    flage=[self.fmDb executeUpdateWithFormat:@"insert into myRecord(pID,timer) values(%d,%@)",self.Mypoem.poemID,currentTime];
     
    2、用问号代替字段,拼接方式:executeUpdate
    NSString * sql = @"insert into user (name, password) values(?, ?) ";
    NSString * name = [NSString stringWithFormat:@"queue111 %d", i];
    BOOL res = [db executeUpdate:sql, name, @"boy"];
    if (!res) {
        debugLog(@"error to add db data: %@", name);
    else {
        debugLog(@"succ to add db data: %@", name);
    }
    //----------------------------delete-删除数据------------------------------------------
    删除某条语句
    BOOL flag = [self.fmdb executeUpdate:@"DELETE FROM test_tab WHERE name=?",@"jiajia"];
     
    删除表
    BOOL flag = [self.fmdb executeUpdate:@"DELETE FROM test_tab];
    //----------------------------update-修改数据------------------------------------------
    修改数据:
    格式:update 表名 SET 修改内容 where 条件
    update foods SET id = 800 - id
     
    //----------------------------select-查询数据------------------------------------------
    1、查询指定数据:executeQueryWithFormat
    [self.fmDb open];
    NSLog(@"%d",_Mypoem.poemID);
    FMResultSet *poemRSet=[self.fmDb executeQueryWithFormat:@"select D_SHI,D_INTROSHI from T_SHI where D_ID = %d",self.Mypoem.poemID];
    while ([poemRSet next]) {
        NSString *temp1=[poemRSet stringForColumn:D_SHI];
        NSString *temp2=[poemRSet stringForColumn:D_INTROSHI];
        self.textView.text=[temp1 stringByAppendingString:temp2];
        NSLog(@"%@",[temp1 stringByAppendingString:temp2]);
    }
    [self.fmDb close];
     
    2、查询个数:(只会返回一个值):executeQuery
    1)select count(*) allrecord from myRecord   //allrecord:给字段的取别名
     
    2)查询指定的个数:executeQueryWithFormat
    FMResultSet *resultSet=[self.fmDb executeQueryWithFormat:@"select count(pID) allCollection from myCollection where pID = %d",self.Mypoem.poemID];
    NSLog(@"self.Mypoem.poemID = %d",self.Mypoem.poemID);
    [resultSet next];
    int count=[resultSet intForColumn:@"allCollection"];
    NSLog(@"判断是否已经存在了这条记录:%d",count);
     
    3、
    sql = @"INSERT INTO USER (name,phone,idcode) VALUES (?,?,?) ";
    BOOL res = [db executeUpdate:sql,nameTextField.text,phoneTextField.text,IDTextField.text];
    if (!res) {
        NSLog(@"error to insert data");
        mes = @"数据插入错误";
    }else{
        NSLog(@"insert succeed");
        mes = @"数据插入成功";
    }
    4、
    FMResultSet *resultSet = [self.fmdb executeQuery:@"SELECT * FROM emp WHERE id > ?"@2];
    while([resultSet next]){//取一条记录
        //取这条记录中的每个字段值
        int ID = [resultSet intForColumn:@"id"];
        NSString *name = [resultSet stringForColumn:@"name"];
        int age = [resultSet intForColumn:@"age"];
        double salary = [resultSet doubleForColumn:@"salary"];
        self.displayLabel.text = [self.displayLabel.text stringByAppendingFormat:@" %d,%@,%d,%.2lf", ID, name, age, salary];
    }
    [self.fmdb close];
     
     
     
    //—————-----------------———补充:多表关联 ---------------------------------
    //———————方式一:
    1、支持多表连接,例如
    select * from student,class where student.cid=class.id;
    select table1.abc from table1,table2 where table1.xxx=table2.xxx;
    例子:
    关于sqlite 多表查询的,有3个表
    A
        id user
        1  admin
        2  guest
    B
        id app_name version
        1  app_1    1.1
        2  app_2    1.3
        3  app_3    1.4
    C
        id user_id app_name_id
        1  1      1
        2  2      2
        3  1      3
    要求:通过SELECT把A表中admin使用的app的app_name和version显示出来 
    SQL语句:
    select A.user,B.app_name,B.version from A,B,C where A.user='admin' and A.id=C.user_id and C.app_name_id=B.id
    //———————方式二:
    2、 inner join table on 
    记录一下sqlite中多表查询。
    1:品牌:brands( brandid vARCHAR(20),
                 brand VARCHAR(20),
                 remark vARCHAR(100))
    2:类型:types( typeid vARCHAR(20),
                type VARCHAR(20),
                remark vARCHAR(100))
    3:品牌:levels( levelid vARCHAR(20),
                 level VARCHAR(20),
                 remark vARCHAR(100))
    4:油品:oils( oilid vARCHAR(20),brandid VARCHAR(20),typeid vARCHAR(20),levelid vARCHAR(20),remark vARCHAR(100))
    说明一下:前三个表为基本信息,即油品的品牌、类型、级别,表4为油品信息,那么该如何显示油品的基本信息呢?
    select brands.brand,types.type,levels.level from oils
    inner join brands on oils.brandid = brands.brandid
    inner join types on oils.typeid =types.typeid
    inner join levels on oils.levelid =levels.levelid
     
    再如:
    select table1.abc from table1 inner join table2 on table1.xxx=table2.xxx;
     
    //———————方式三:
    3、支持左外连接(left outer join)
    例如:
    select * from foods
    left outer join food_types
    on foods.id=food_types.food_id
    4、不支持右外连接和全连接。
    //  唐诗三百
    [self.fmdb open];
    NSString *sql=nil;
    if ([self.myType isEqualToString:@"myCollection"]==YES) {
    //我的收藏
    要特别注意:是对哪些表进行操作的
        sql=@"select T_SHI.D_AUTHOR,T_SHI.D_KIND,T_SHI.D_TITLE,T_SHI.D_ID,myCollection.timer from T_SHI,myCollection where T_SHI.D_ID = myCollection.pID";
    }else{
    //我的记录
        sql=@"select T_SHI.D_AUTHOR,T_SHI.D_KIND,T_SHI.D_TITLE,T_SHI.D_ID,myRecord.timer from T_SHI,myRecord where T_SHI.D_ID = myRecord.pID";
    }
    NSLog(@"SQL = %@",sql);
    FMResultSet *poemRSet=[self.fmdb executeQuery:sql];
    //    NSLog(@"错误:%@",[self.fmdb lastError]);
    while ([poemRSet next]) {
        Poem *newPoem=[[Poem alloc]init];
        newPoem.poemAuthor=[poemRSet stringForColumn:D_AUTHOR];
        newPoem.poemKind=[poemRSet stringForColumn:D_KIND];
        newPoem.poemTime=[poemRSet stringForColumn:TIMER];
        newPoem.poemTitle=[poemRSet stringForColumn:D_TITLE];
        newPoem.poemID=[poemRSet intForColumn:D_ID];
        NSLog(@"%@",[newPoem description]);
        [self.allPoemInfo addObject:newPoem];
    }
    [self.fmdb close];
    //------------------------------------End---------------------------------------------
    fmdb-master.zip
    101.2 KB

     

    摘要:FMDatabaseQueue、事务处理
    FMDatabaseQueue 及线程安全
    在多个线程中同时使用一个FMDatabase实例是不明智的。现在你可以为每个线程创建一个FMDatabase对象。 不要让多个线程分享同一个实例,它无法在多个线程中同时使用。 若此,坏事会经常发生,程序会时不时崩溃,或者报告异常,或者陨石会从天空中掉下来砸到你Mac Pro.  总之很崩溃。所以,不要初始化FMDatabase对象,然后在多个线程中使用。请使用 FMDatabaseQueue,它是你的朋友而且会帮助你。以下是使用方法:
    首先创建队列。
    //-----------------------------队列FMDatabaseQueue------------------------------------------
    使用队列FMDatabaseQueue
         在多线程环境下,为了防止同时执行SQL语句时发生冲突,可以考虑使用FMDatabaseQueue来执行SQL语句。
    inDatabase:^(FMDatabase *db){在这里执行SQL语句},操作过程都是相同的
     
    NSString *dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectoryNSUserDomainMaskYES)firstObject]stringByAppendingPathComponent:@"demo4.db"];
    self.dbPath = dbPath;
    //相当于一个FMDatabase对象
    self.queue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
    1)创建表
    [self.queue inDatabase:^(FMDatabase *db) {
        BOOL res = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS person(id integer PRIMARY KEY, name text NOT NULL)"];
        if(res){
            NSLog(@"建表成功");
        }else{
            NSLog(@"建表失败");
        }
    }];
    2)插入值
    [self.queue inDatabase:^(FMDatabase *db) {
        [db executeUpdate:@"INSERT INTO person(name) VALUES(?)"@"Daniel"];
    }];
     
    3)查询:
    [self.queue inDatabase:^(FMDatabase *db) {
        FMResultSet *resultSet = [db executeQuery:@"SELECT * FROM person"];
        while ([resultSet next]) {
            int ID = [resultSet intForColumn:@"id"];
            NSString *name = [resultSet stringForColumn:@"name"];
            NSLog(@"ID:%d,name:%@", ID, name);
        }
    }];
     
    //一段查询数据库的代码
    NSString *dbPath=[[NSBundle mainBundle]pathForResource:@"poem" ofType:@"db"];
    if (dbPath == nil) {
        NSLog(@"没有找到数据库!");
    }
    NSLog(@"dbpath = %@",dbPath);
    FMDatabase *fmdb=[FMDatabase databaseWithPath:dbPath];//获取数据库
    [fmdb open];//打开数据库
    NSLog(@"%d",_Mypoem.poemID);
    FMResultSet *poemRSet=[fmdb executeQueryWithFormat:@"select D_SHI,D_INTROSHI from T_SHI where D_ID = %d",self.Mypoem.poemID];//条件查询:where D_ID == self.Mypoem.poemID 的记录,记得需要使用格式化的语句:executeQueryWithFormat
    while ([poemRSet next]) {//获取一条语句[poemRSet next]的返回值是BOOL类型的
        NSString *temp1=[poemRSet stringForColumn:D_SHI];//读取字段为D_SHI下的内容
        NSString *temp2=[poemRSet stringForColumn:D_INTROSHI];//读取字段为D_INTROSHI下的内容
        self.textView.text=[temp1 stringByAppendingString:temp2];//拼接后,赋值给self.textView.text
        NSLog(@"%@",[temp1 stringByAppendingString:temp2]);
    }
    [fmdb close];//有打开,就要有关闭
    //--------------------------------------------------------------------------------
    事务处理(Transaction)
    FMDatabase *db = [FMDatabase databaseWithPath:self.dbPath];
    [db open];
    //开始一个事务
    [db beginTransaction];
    [db executeUpdate:@"INSERT INTO person(name) VALUES(?)"@"Shasha"];
    //如果在执行某条SQL语句时出现问题,由于我们处在一个事务中,所以执行成功的SQL会自动回滚(恢复以前的数据)
    //[db rollback];//主动回滚
     [db executeUpdate:@"INSERT INTO person(name) VALUES(?)"@"Shanshan"];
    //提交一个事务
    [db commit];
    //在队列中执行事务
    [self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
        [db executeUpdate:@"INSERT INTO person(name) VALUES(?)"@"AAA"];
        [db executeUpdate:@"INSERT INTO person(name) VALUES(?)"@"BBB"];
        //*rollback = YES;//主动回滚
    }];
  • 相关阅读:
    NPOI创建DOCX常用操作
    【Python】django多对多 查询 ,反查等操作
    【Python】python 普通继承方式和super继承方式
    【云计算】开源装机自动化系统 CloudBoot OSInstall 介绍
    【Python】Python AES 对称加密示例
    【Python】Django 如何直接返回404 被 curl,wget 捕获到
    【Python】Django 支持 restful 风格 url
    【Python】Django 聚合 Count与Sum用法,注意点
    【Python】使用 boto 调用 S3 对象存储API
    【Other】千字文 硬笔 楷书 字帖
  • 原文地址:https://www.cnblogs.com/lignpeng/p/5458337.html
Copyright © 2020-2023  润新知