zoukankan      html  css  js  c++  java
  • iOS数据库FMDB操作

    1、获取操作对象、获取创建数据库

    • 1.1 获取操作对象、获取数据库

      • CHFmdb.h
      #import <Foundation/Foundation.h>
      
      NS_ASSUME_NONNULL_BEGIN
      
      // 数据库管理器
      #define CHDbMgr   [CHFmdb shareInstance].fmdb
      // 数据库管理队列,该对象支持多线程操作
      #define CHDbQueue   [CHFmdb shareInstance].queue
      
      @interface CHFmdb : NSObject
      
      /** 数据库管理器 */
      @property(nonatomic, strong) FMDatabase *fmdb;
      /** 数据库管理队列,该对象支持多线程操作 */
      @property(nonatomic, strong) FMDatabaseQueue *queue;
      
      + (instancetype)shareInstance;
      
      @end
      
      NS_ASSUME_NONNULL_END
      
      • CHFmdb.m
        • 根据原数据库文件,拷贝数据库到沙盒文件夹,得到应用内部的数据库文件。这种方式通常应用表现在:提供电子书内容源文件用于展示。
      #import "CHFmdb.h"
      
      @interface CHFmdb ()
      
      @end
      
      #define DataBaseName   @"OutLibrary"
      
      @implementation CHFmdb
      
      + (instancetype)shareInstance {
          static CHFmdb *fmdbMgr = nil;
          static dispatch_once_t onceToken;
          dispatch_once(&onceToken, ^{
              fmdbMgr = [[self alloc] init];
      
              // 判断是否存在数据库,如果有,就继续,如果没有就将工程里面的复制到Document
              // 获取所有文档路径
              NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
              // 获取第一个路径
              NSString *docPath = [searchPaths objectAtIndex:0];
              // 拼接完整路径
              NSString *dbPath = [docPath stringByAppendingPathComponent:@"BookLibrary.db"];
      
              // 创建文件管理器
              NSFileManager *fileManager = [[NSFileManager alloc] init];
              // 判断该路径上是否存在数据库
              BOOL isExit = [fileManager fileExistsAtPath:dbPath];
              // 如果不存在,讲工程里面数据库的复制到Document里面
              if (!isExit) {
                  // 获取工程里面的数据库路径
                  NSString *bundleDBPath = [[NSBundle mainBundle] pathForResource:DataBaseName ofType:@"db"];
                  // 拷贝工程里面的数据库到沙盒
                  BOOL success = [fileManager copyItemAtPath:bundleDBPath toPath:dbPath error:nil];
                  if (success) {
                      //CHLog(@"数据库复制成功");
                  }
              }
      
              // 根据数据库路径创建数据库管理器
              fmdbMgr.fmdb = [[FMDatabase alloc] initWithPath:dbPath];
              // 为数据库设置缓存,提高查询效率
              [fmdbMgr.fmdb setShouldCacheStatements:YES];
              
              // 根据数据库路径创建数据库管理队列,该对象支持多线程操作
              fmdbMgr.queue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
          });
          return fmdbMgr;
      }
      
      @end
      
    • 1.2 创建数据库

      • CHFmdb.m
        • 根据数据库文件路径获取数据库管理器,数据库不存在则自动根据路径创建。这种方式通常应用表现在:保存个人喜好,健康数据等。
      #import "CHFmdb.h"
      
      @interface CHFmdb ()
      
      @end
      
      @implementation CHFmdb
      
      + (instancetype)shareInstance {
          static CHFmdb *fmdbMgr = nil;
          static dispatch_once_t onceToken;
          dispatch_once(&onceToken, ^{
              fmdbMgr = [[self alloc] init];
      
              // 判断是否存在数据库,如果有,就继续,如果没有就将工程里面的复制到Document
              // 获取所有文档路径
              NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
              // 获取第一个路径
              NSString *docPath = [searchPaths objectAtIndex:0];
              // 拼接完整路径
              NSString *dbPath = [docPath stringByAppendingPathComponent:@"BookLibrary.db"];
      
              // 根据数据库路径创建数据库管理器
              fmdbMgr.fmdb = [[FMDatabase alloc] initWithPath:dbPath];
              // 为数据库设置缓存,提高查询效率
              [fmdbMgr.fmdb setShouldCacheStatements:YES];
              
              // 根据数据库路径创建数据库管理队列,该对象支持多线程操作
              fmdbMgr.queue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
          });
          return fmdbMgr;
      }
      
      @end
      

    2、FMDatabase 详细操作

    • 2.0 创建表

      • 先判断表是否存在,不存在再创建。属性修饰:字符串用->TEXT, 整型值用->INTEGER。
      • 创建 t_ReadHistory 表,属性有自动增长唯一的ID, 书本ID:bookId, 书名:bookName, 阅读时间:readTime
      if ([CHDbMgr open]) {
          NSString *sqlStr = NSStringFormat(@"CREATE TABLE IF NOT EXISTS t_ReadHistory(id INTEGER PRIMARY KEY AUTOINCREMENT, bookId INTEGER, bookName TEXT, readTime TEXT);");     
          BOOL success = [CHDbMgr executeUpdate:sqlStr];
      }
      
    • 2.1 增 insert into

      • executeUpdate:不确定的参数用?来占位(后面参数必须是oc对象,“;”代表语句结束)
        • 例如基础数据类型的要加 “@(xxx)”转成对象类型NSNumber。
        if ([CHDbMgr open]) {
            [CHDbMgr executeUpdate:@"insert into t_ReadHistory(bookId, bookName, readTime) values(?,?,?);" , @(1001), @"西游记", @"2020年06月23日"];  
        }
        
      • executeUpdateWithForamat:不确定的参数用%@,%d等来占位(参数为原始数据类型,执行语句不区分大小写)
        if ([CHDbMgr open]) {
            [CHDbMgr executeUpdateWithForamat:@"insert into t_ReadHistory(bookId, bookName, readTime) values(%ld, %@, %ld);", @(1001), @"西游记", @"2020年06月23日"]; 
         }
        
      • 参数是数组的使用方式
        if ([CHDbMgr open]) {
            [CHDbMgr executeUpdate:@"insert into t_ReadHistory (bookId, bookName, readTime) values(?, ?, ?);" withArgumentsInArray:@[@(1001), @"西游记", @"2020年06月23日"]];
        }
        
    • 2.2 删 delete

      • 不确定的参数用?来占位 (后面参数必须是oc对象,需要将int包装成OC对象)
      if ([CHDbMgr open]) {
          [CHDbMgr executeUpdate:@"delete from t_ReadHistory where bookId = ?;", @(1001)];
      }
      
      • 不确定的参数用%@,%d等来占位
      if ([CHDbMgr open]) {
          [CHDbMgr executeUpdateWithFormat:@"delete from t_ReadHistory where bookName = %@;", @"西游记"];
      }
      
    • 2.3 查 select ... from

      if ([CHDbMgr open]) {
          // FMResultSet结果集
          FMResultSet *set = [CHDbMgr executeQuery:@"select bookId, bookName, readTime from t_ReadHistory;"];
          // next 返回yes说明有数据
          if ([set next]) { 
              NSInteger bookId = [set intForColumn:@"bookId"];
              NSString *bookName = [set stringForColumn:@"bookName"];
              NSString *readTime = [set stringForColumn:@"readTime"];
          }
          else {
              CHLog(@"查询出错");
          }
      }
      
      • 查询说明
        • select命令就是查询,执行查询的方法是以-excuteQuery开头的。
        • 执行查询时,如果成功返回FMResultSet对象,错误返回nil。
        • 与执行更新相当,支持使用NSError参数。
        • 同时,你也可以使用-lastErrorCode和-lastErrorMessage获知错误信息。
      • FMResultSet获取不同数据格式的方法:
      intForColumn:
      longForColumn:
      longLongIntForColumn:
      boolForColumn:
      doubleForColumn:
      stringForColumn:
      dataForColumn:
      dataNoCopyForColumn:
      UTF8StringForColumnIndex:
      objectForColumn:
      
      • 查询符合要求的结果条数
      if ([CHDbMgr open]) {
          // 查符合条件的书的总数
          sqlStr = @"select COUNT(*) from t_ReadHistory where bookId = ?;";
          NSUInteger bookCount = [CHDbMgr intForQuery:sqlStr, @(1001)];
      }
      
    • 2.4 改 update

    if ([CHDbMgr open]) {
        [CHDbMgr executeUpdate:@"update t_ReadHistory set bookName = ? where bookId = ?", @"红楼梦", @(1001)];
    }
    
    • 2.5 删除表 drop ...

    if ([CHDbMgr open]) {
        // 如果表格存在 则销毁 
        [CHDbMgr executeUpadate:@"drop BookLibrary if existst t_ReadHistory;"];
    }
    
    • 2.6 当添加了一列数据时,如果有需要,获取自增的id:

    if ([CHDbMgr open]) {
        BOOL success = [CHDbMgr executeUpdate:@"insert into t_ReadHistory(bookId, bookName, readTime) values(?,?,?);" , @(1001), @"西游记", @"2020年06月23日"];  
        if (success) {
            // 此处为刚才添加的自增id号
            NSInteger logid = CHDbMgr.lastInsertRowId;
            CHLog(@"NSInteger == %ld", logid);
        }
    }
    

    3、FMDatabaseQueue类 实现多线程操作

    • 在多个线程中同时使用一个FMDatabase实例是不明智的。现在你可以为每个线程创建一个FMDatabase对象,不要让多个线程分享同一个实例,他无法在多个线程中同事使用。否则程序会时不时崩溃或者报告异常。所以,不要初始化FMDatabase对象,然后在多个线程中使用。这时候,我们就需要使用FMDatabaseQueue来创建队列执行事务。
    • 创建表
    // 会通过block传递队列中创建好的数据库给我们
    [CHDbQueue inDatabase:^(FMDatabase *db) {
        // 编写需要执行的代码
        NSString *sqlStr = NSStringFormat(@"CREATE TABLE IF NOT EXISTS t_ReadHistory(id INTEGER PRIMARY KEY AUTOINCREMENT, bookId INTEGER, bookName TEXT, readTime TEXT);");     
    
        BOOL success = [db executeUpdate:sqlStr];
        if (success) {
            CHLog(@"创建表成功");
        }
        else {
            CHLog(@"创建表失败");
        }
    }];
    
    • 多任务操作
    // 会通过block传递队列中创建好的数据库给我们
    [CHDbQueue inDatabase:^(FMDatabase *db) {
        // 编写需要执行的代码
        [db executeUpdate:@"insert into t_ReadHistory(bookId, bookName, readTime) values(?,?,?);" , @(1001), @"西游记", @"2020年06月23日"];  
        [db executeUpdate:@"insert into t_ReadHistory(bookId, bookName, readTime) values(?,?,?);" , @(1002), @"三国演义", @"2020年06月23日"];  
    }];
    
  • 相关阅读:
    [模板]大数加法
    HDU 1848 Fibonacci again and again
    同时安装了Python2和Python3时的pip使用
    UPC-2785 One-Way Roads(最大流建图)
    UPC-2784 Model Railroad(最小生成树)
    【ICPC 2017 Daejeon】UPC-9312 Game Map(dfs)
    【ICPC 2015 Shenyang】UVALive
    【ICPC 2015 Shenyang 】UPC-9254 MEETING(最短路&虚点建图)
    UPC-9264 Chip Factory(01字典树)
    【ICPC 2018 Malaysia】UPC-9302 ELI'S CURIOUS MIND(递推)
  • 原文地址:https://www.cnblogs.com/CH520/p/13179204.html
Copyright © 2011-2022 走看看